mirror of
https://github.com/germondai/trawl.git
synced 2026-08-17 12:11:23 +02:00
10 KiB
10 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.
[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 every request through the browser pool so clients like Prowlarr / Sonarr / Jackett / JDownloader / ChangeDetection can hit fingerprint-bound Cloudflare sites (e.g. 1337x) that the/v1cookie-handoff can't. CA + leaf certs self-generated and persisted; CA 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 binds to
127.0.0.1by default;MITM_PROXY_HOSTenv override for non-local docker-network setups. 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