# Lite Engine: Chrome-Free DOM Capture using Gost-DOM **Branch:** `feat/lite-engine-gostdom` **Issue:** [#201](https://github.com/pinchtab/pinchtab/issues/201) **Related Draft PR:** [#200](https://github.com/pinchtab/pinchtab/pull/200) **Dependency:** [gost-dom/browser v0.11.0](https://github.com/gost-dom/browser) (MIT, ~255 stars, Go 78.4%) --- ## Overview This implementation adds a **Lite Engine** that can perform DOM capture (navigate, snapshot, text extraction, click, type) without requiring Chrome/Chromium. It uses [Gost-DOM](https://github.com/gost-dom/browser), a headless browser written in pure Go, to parse and traverse HTML documents. The architecture follows the maintainer's guidance for **"clever routing that is expandable without touching the rest of the code"** — implemented via a strategy-pattern Router with pluggable rules. ## Architecture ### Engine Interface (`internal/engine/engine.go`) ```go type Engine interface { Name() string Navigate(ctx context.Context, url string) (*NavigateResult, error) Snapshot(ctx context.Context, filter string) ([]SnapshotNode, error) Text(ctx context.Context) (string, error) Click(ctx context.Context, ref string) error Type(ctx context.Context, ref, text string) error Capabilities() []Capability Close() error } ``` ### Router (`internal/engine/router.go`) The Router evaluates an ordered chain of `RouteRule` implementations. The first rule to return a non-`Undecided` verdict wins. ``` Request → Router → [Rule 1] → [Rule 2] → ... → [Fallback Rule] → Engine ``` Rules are hot-swappable at runtime via `AddRule()` / `RemoveRule()` — no handler code changes needed. ### Three Modes | Mode | Behavior | Default Rules | |------|----------|---------------| | `chrome` | All requests → Chrome (default, backward compatible) | DefaultChromeRule | | `lite` | DOM ops → Gost-DOM, screenshots/PDF/evaluate → Chrome | CapabilityRule → DefaultLiteRule | | `auto` | Per-request routing based on URL patterns | CapabilityRule → ContentHintRule → DefaultChromeRule | ### Built-in Rules (`internal/engine/rules.go`) | Rule | Purpose | |------|---------| | `CapabilityRule` | Routes screenshot/pdf/evaluate/cookies → Chrome (lite can't do these) | | `ContentHintRule` | Routes `.html/.htm/.xml/.txt/.md` URLs → Lite (for navigate/snapshot/text) | | `DefaultLiteRule` | Catch-all: routes all DOM ops → Lite | | `DefaultChromeRule` | Final fallback: routes everything → Chrome | ### Expandability Adding new routing logic requires only: 1. Implement `RouteRule` interface (2 methods: `Name()`, `Decide()`) 2. Call `router.AddRule(myRule)` — inserted before the fallback rule No handler, config, or CMD changes needed. ## Files Changed ### New Files (8) | File | Purpose | Lines | |------|---------|-------| | `internal/engine/engine.go` | Engine interface, types, capabilities | ~70 | | `internal/engine/lite.go` | LiteEngine implementation using Gost-DOM | ~430 | | `internal/engine/router.go` | Router with AddRule/RemoveRule | ~120 | | `internal/engine/rules.go` | 4 built-in RouteRule implementations | ~95 | | `internal/engine/lite_test.go` | LiteEngine unit tests | ~280 | | `internal/engine/router_test.go` | Router unit tests | ~130 | | `internal/engine/rules_test.go` | Rule unit tests | ~115 | | `internal/engine/realworld_test.go` | Real-world website comparison tests | ~570 | ### Modified Files (8) | File | Change | |------|--------| | `internal/config/config.go` | Added `Engine` field to RuntimeConfig + ServerConfig | | `internal/handlers/handlers.go` | Added `Router *engine.Router` field, `useLite()` helper | | `internal/handlers/navigation.go` | Lite fast path before ensureChrome | | `internal/handlers/snapshot.go` | Lite fast path with SnapshotNode → A11yNode conversion | | `internal/handlers/text.go` | Lite fast path returning plain text | | `cmd/pinchtab/cmd_bridge.go` | Engine router wiring based on config mode | | `go.mod` | Added gost-dom/browser v0.11.0, gost-dom/css v0.1.0 | | `go.sum` | Updated checksums | ## Improvements Over PR #200 Draft | Area | PR #200 | This Implementation | |------|---------|-------------------| | Tab management | Single window | Multi-tab with sequential IDs | | HTML parsing | `browser.Open()` double-fetches | HTTP fetch → strip scripts → `html.NewWindowReader` | | Script handling | Panics on `