mirror of
https://github.com/germondai/trawl.git
synced 2026-08-17 12:11:23 +02:00
16 KiB
16 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Fixed
- Translate Prowlarr's serialized
headers.contentTypemetadata at the FlareSolverr/v1compatibility boundary and discardcontentLength, allowing form POST requests to enter the scraper pipeline (#50). - Bound Camoufox memory growth by counting every Tier 3/4 temporary context and rolling-replacing browsers at
BROWSER_RECYCLE_AFTER_CONTEXTS, while keeping existing capacity available during warm-up. Replacement launches are serialized, cleanup is timeout-bounded, and failed launches retain the usable browser (#52).
[1.3.1] - 2026-08-02
Fixed
- Keep pooled browser contexts under
BrowserPoolownership so repeat Tier 2 requests cannot reuse a context closed by a separate cache (#45).
Changed
- Bump all application and internal package versions to
1.3.1.
[1.3.0] - 2026-08-02
Added
- Detect and resolve Akamai Bot Manager behavioral interstitials across scraper tiers and the HTTP/HTTPS proxy (#33).
- Document supported upstream proxy formats, local Compose configuration, and residential proxy pools (#26).
Fixed
- Reject non-object request bodies and missing, non-string, or blank
urlvalues with HTTP 400 before scraper-tier execution (#34). - Recover stalled browser checkouts and bound browser close/launch operations so wedged Firefox processes cannot silently exhaust the pool (#36, #37, #48).
- Report HTTP 503 from
/healthwhenever the browser pool has no live capacity. - Pass authenticated proxy credentials to Firefox separately from the proxy server URL in Tier 3 and Tier 4 (#40).
- Return complete Tier 1 text responses instead of the 4 KiB challenge-detection preview (#46, #47).
- Record the correct architecture-specific Camoufox release metadata in API images.
Changed
- Bump all application and internal package versions to
1.3.0. - Update workspace dependencies to their latest compatible releases. TypeScript remains on 5.9 for the Nuxt app until
vue-tscsupports TypeScript 7.
[1.2.0] - 2026-07-26
Added
- Tier 0 direct forward in the MITM proxy (
apps/api/src/proxy/directForward.ts): the proxy at:8192now forwards requests directly to upstream via raw TCP/TLS instead of spinning up a browser for every request. Pool is reserved for the requests that actually need CF bypass; Netflix/YouTube/banks/etc. flow at near-direct speed. - Smart adaptive streaming (
apps/api/src/proxy/streaming.ts): small JSON/HTML/text responses are buffered so the challenge detector can inspect them; video/audio/binary files (.mp4,.mkv,.m3u8,.zip,.exe,.dmg, etc.) are streamed straight through to the client. Default threshold: 8 MiB. - Per-hostname challenge cache (
apps/api/src/proxy/challengeCache.ts): the proxy remembers which hostnames recently returned Cloudflare challenges and sends repeat visits directly to the tiered solver for 5 minutes. - Persistent browser context cache: solved sessions retain their browser fingerprint, cookies, cache, and storage across proxy requests, with bounded per-proxy reuse and cleanup.
- General HTTP/HTTPS proxy support: CONNECT tunneling, plain HTTP absolute-form requests, WebSocket upgrades, request bodies, redirects, authentication headers, cookies, and HTTP Range/206 responses are forwarded with their required semantics.
proxySanitizeHeaders()(packages/tiers/src/utils/sanitize.ts): permissive header sanitizer for the transparent MITM proxy — passesAuthorization,Cookie,Range,User-Agent,Referer, and custom API tokens through, strips only RFC 7230 hop-by-hop headers.- Raw bytes in
@trawl/tiers:ScrapeResultand tier results now exposebody?: Uint8Array,responseHeaders?: Record<string,string>, andcontentType?: stringalongside the existinghtmlfield. The proxy uses these fields to preserve binary content without HTML normalization. - Tier 1 method handling fix:
runTier1()now forwards the request body forPUT,PATCH,DELETE,QUERY(was onlyPOST). - Graceful proxy shutdown (
shutdownMitmProxy()): the API captures the proxy handle on startup andlifecycle.tscallsshutdownMitmProxy()onSIGTERM/SIGINTbefore the browser pool shutdown, so in-flight connections drain. - MITM proxy port + CA volume in docker-compose:
8192:8192port mapping,MITM_PROXY_*env vars, and a persistenttrawl_proxy_cavolume so the CA survives container restarts. - Proxy tests: header sanitization, response policy, adaptive streaming, challenge caching, direct HTTP forwarding, Range/206 handling, chunked responses, compressed challenge detection, and explicit media streaming.
- Proxy documentation: architecture, configuration, client setup, and CA installation guides for operating systems, browsers, Java/JDownloader, containers, and application-specific trust stores.
Changed
packages/types/src/index.ts—ScrapeResultextended additively with optionalbody,responseHeaders, andcontentType; native/scrapeconsumers should tolerate these additional fields.apps/api/src/proxy/server.ts—fetchRaw/reissuereplaced byproxyRequest()(Tier 0 withscrape()fallback) for both CONNECT-based HTTPS and plain HTTP traffic.lifecycle.ts—registerLifecycleHandlers()accepts an optional{ onShutdown }callback.apps/api/src/index.ts— captures the proxy handle on startup and wires it intoregisterLifecycleHandlers.- All application and internal package versions bumped to
1.2.0.
[1.1.0] - 2026-07-22
Added
- Browser-backed MITM forward-proxy mode (
MITM_PROXY_ENABLED, off by default): HTTP(S) forward proxy that re-issues requests through the browser pool so clients like Prowlarr, Jackett, JDownloader, and changedetection.io can hit fingerprint-bound Cloudflare sites that the/v1cookie handoff cannot. The generated root CA is persisted, per-host certificates are minted in memory, and the root is downloadable atGET /proxy-ca.crt. New env:MITM_PROXY_{ENABLED,PORT,HOST,CA_DIR,MAX_TIER,DEBUG}.
Changed
fetchRawrotatesproxyPoolon Cloudflare challenge (samemarkBad → next()pattern as Tier 3) instead of retrying on the same IP.- Main MITM proxy listener supports a configurable bind address through
MITM_PROXY_HOST. ci.ymlruns on PRs targetingdevin addition tomain.publish.ymlinspects the actually-pushed tag fromdocker/metadata-actioninstead of re-deriving fromgithub.sha(which previously mismatched the 7-char short SHA).node-forge ^1.3.1runtime dep for CA + per-host leaf cert generation.
[1.0.1] - 2026-07-18
Changed
packages/browser/src/pool.ts— renamed Firefox prefs key fromprefs(silently ignored by camoufox-js@0.11.1) tofirefox_user_prefs(which camoufox-js maps to Playwright'sfirefoxUserPrefs). The prefs are now actually applied.packages/browser/src/pool.ts— added the safe-only subset of Firefox prefs: telemetry off (datareporting.*,toolkit.telemetry.*,app.crashreporter,breakpad.*), dead UI features off (extensions.screenshots.*,browser.sessionstore.max_tabs_undo), dead network services off (browser.safebrowsing.*,extensions.update.*,browser.fixup.alternate.*,app.normandy.*,app.shield.*,network.connectivity-service.*,network.captive-portal-service.*,network.prefetch-next,beacon.enabled),security.OCSP.enabled: 0, and tightened network timeouts (tls-handshake-timeout: 30,connection-timeout: 60,response.timeout: 120). None of these touch the JS/CSS fingerprint surface.apps/api/Dockerfile— stage-3 prune of apt cache +/usr/share/{locale,doc,man}(image-size win, runtime-neutral).apps/api/Dockerfile— added 9 Bun runtime ENV flags (BUN_DISABLE_CJS=1,BUN_DEBUG=0,BUN_DISABLE_SOURCEMAPS=1,BUN_HTTP_KEEPALIVE=0,BUN_AGENT_DISABLE=1,BUN_INSPECT=0,BUN_LOCKFILE_MIGRATION=false,MIMALLOC_PURGE_DELAY=0,NODE_NO_WARNINGS=1). All verified runtime-neutral in smoke tests.packages/browser/package.json— movedpatchright+playwright-corefromdependenciestodevDependencies(build hygiene; camoufox-js bundles both transitively at runtime).- All packages bumped to
1.0.1.
Added
scripts/bench-targets.sh,scripts/bench-success-rate.sh,scripts/bench-compare.sh— observability harnesses for measuring CF challenge latency + bypass success rate.
[1.0.0] - 2026-07-10
Changed
- Shared types (
BrowserHandle,BrowserFingerprint,SupportedMethod) centralized instead of being duplicated per-package packages/tierssplit intotiers/andutils/, deduplicating cookie and network-failure helpers;apps/api's entrypoint split intoconfig,deps, androutes, adding a proper root status route- Evaluated switching the cache backend to Dragonfly and reverted:
benchmarking showed Dragonfly only wins throughput when load is spread across multiple
connections, but
packages/browser'sSessionCacheholds a single sharedRedisClientconnection for the process lifetime — so at TRAWL's actual access pattern, plain Redis is faster at every scale tested, regardless ofBROWSER_POOL_SIZE. Docker Compose configs (docker-compose.yml,.full.yml,.prod.yml) now pinredis:8.8-alpine; theredisservice name andREDIS_URLenv var are unchanged from before the Dragonfly experiment.
Added
- Landing page shows a live GitHub star count
[0.7.0] - 2026-07-08
Added
- Audio STT fallback for the hCaptcha solver
Fixed
- JS-only challenge pages that only look like plain HTML now correctly escalate from Tier 1 to the browser tiers (#22, #23)
[0.6.0] - 2026-07-08
Added
BROWSER_RECYCLE_AFTER_CONTEXTSenv var (default8, set0to disable) bounds long-running browser process growth by recycling the pooled Camoufox/Firefox instance after a configurable number of Tier 3/Tier 4 temporary context creationsBROWSER_CONTENT_PROCESSESenv var (default2) caps Firefox content processes per pooled browser via thedom.ipc.processCountFirefox pref. Firefox's default of 8 lets thread count climb when Tier 3/Tier 4 churn disposable contexts (see #13). The cap bounds the leak at the source without needing to restart the browser.- Browser fingerprints now randomize OS/screen/window per instance and match the HTTP
User-Agentto the emulated platform
Changed
BROWSER_RECYCLE_AFTER_CONTEXTSno longer recycles preemptively after every N temporary contexts. The pool now recycles only when Tier 3 or Tier 4 returns ablocked/needs-jsoutcome, preserving cookies,cf_clearance, and warm fingerprint state across successful solves. This eliminates the HTTP-429 storm observed in single-browser setups where the previous "recycle every N uses" logic left the only browserrestarting=truefor ~13s during every recycle window (#17, thanks @CoolDotty)- Tier detection now recognizes more block/error page variants; Tier 4 gains full captcha parity, with proxy/timing info surfaced in responses (#19, thanks @edasque)
Fixed
- Missing
curlin the API runtime image broke healthchecks (#20, #21) - Missing GeoLite2 mmdb caused a GeoIP startup crash on boot; now baked into the image (#20, #21)
[0.5.0] - 2026-07-06
Added
- Native
method+bodysupport across all four scraper tiers — theFlareSolverrRequest.cmd=request.postbody is now actually delivered upstream instead of being silently dropped (thanks @whoshoe for the original POST support) ScrapeRequest.methodaccepts the full standard verb set:GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE,QUERY(RFC 9341).CONNECTis intentionally excluded (tunneling verb, inappropriate for a proxy)- POST /
*request bodies are forwarded uncapped — operators who want a byte ceiling should impose it at their ingress / fronting proxy - Body-bearing requests require a
Content-Typeheader; the tier functions no longer auto-injectapplication/x-www-form-urlencoded, which previously mislabelled JSON / XML bodies ScrapeRequestfield renamed frompostData→bodyfor REST-idiomatic naming. (FlareSolverrRequest.postDatais unchanged because it's the upstream wire contract.)- Native Imperva/Incapsula WAF challenge detection and solving in Tier 3 and Tier 4
- Proxy rotator reworked into a sticky, failure-aware pool with per-request override support
PORT_APIenv var renamed toPORTand made properly configurable (#9, #10)
Security
- Reserved-name header denylist prevents callers from spoofing
cf_clearancecookies, overriding the per-tierUser-Agent, or rewriting routing signals (X-Forwarded-For,Host) during a POST bypass flow
Fixed
/v1now accepts Prowlarr's CardigannFlareSolverrProxyobject shape ({url, username, password}) for the per-requestproxyfield, instead of crashing withproxy.server: expected string, got objectwhen Prowlarr sends it through (#12, #15). The boundary normalises both the object form and a plain URL string into a single URL string before the orchestrator forwards it to Playwright/Camoufox. Credentials are URL-encoded so embedded@/:characters survive the round-trip.
Limitations
- The Playwright
page.route(url, …)interceptor only handles the first top-frame GET to that exact URL. Server redirects to a different URL, XHR sub-resources, and chainedPOST→POSTform flows do not have thepostDataoverride applied - No idempotency-key support; transient network failures and pool churn can re-fire a POST (separate ticket)
Tests
packages/tiers/tests/sanitize.test.ts— header sanitiser, method allowlist, postData size cap, Content-Type enforcementpackages/tiers/tests/runTier1Post.test.ts— tier1 GET/POST round-trip and User-Agent non-override- Run via
bun --cwd packages/tiers test
[0.4.0] - 2026-07-01
Added
:baselineDocker image variant for pre-AVX2 CPUs and older kernels, published to its own GHCR tag — confirmed working on a Synology DS920+ (DSM 7.3.2, kernel 4.4.302), see #1
Fixed
- Docker healthchecks failing, root-caused to
wgetvs. the runtime image; switched to acurl-based healthcheck with a proper timeout and start period (#3, #4) - Startup crash loop (
EISDIR, missingmemoirist/camoufox-js) fixed by switchingbun installto--linker=hoisted(#1, #6) /healthnow correctly returns 503 while the browser pool is still initializing
[0.3.0] - 2026-06-30
Added
- Configurable browser pool concurrency limiter to guard against OOM under burst load
BROWSER_ACQUIRE_TIMEOUT_MSenv var, default 15s
Changed
- A saturated browser pool now returns HTTP 429 instead of a raw 500
- Default
BROWSER_POOL_SIZEraised to 3
[0.2.0] - 2026-06-26
Added
- Custom
headersfield onScrapeRequest, forwarded through Tier 1-4 via URL-scoped route interception and exposed on/v1and/scrapewith CORS support cmdis now optional on/v1, defaulting torequest.get
Changed
- Multi-arch Docker publish now runs on native arm64 runners with a two-phase per-digest build and manifest merge
[0.1.0] - 2026-06-26
Added
- Initial release with 4-tier execution engine
- Native captcha solving for Cloudflare Turnstile, reCAPTCHA v2 (audio STT), hCaptcha (audio bypass), and GeeTest v3 slider
- Persistent browser pool with real Camoufox Firefox
- Session caching via Redis
- FlareSolverr v2-compatible
/v1endpoint - WebSocket live scrape streaming at
/scrape/live - Self-healing browser pool with automatic restart on crash
- Sticky domain routing to maximize session cache hits
- Nuxt 4 landing page with live stats
- VitePress documentation site
- Docker Compose deployment with amd64/arm64 platform targeting