browser

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrAuthWall = fmt.Errorf("hermai: page requires authentication")

ErrAuthWall is returned when a page requires authentication.

Functions

func DetectAuth

func DetectAuth(signals AuthSignals) bool

DetectAuth returns true if the given signals indicate the page is behind an authentication wall.

Checks (any match returns true):

  1. HTTP 401 or 403
  2. FinalURL contains a login-related path (case-insensitive)
  3. DOMSnapshot contains login-related content (case-insensitive)

Types

type AuthSignals

type AuthSignals struct {
	HTTPStatus  int
	FinalURL    string
	DOMSnapshot string
}

AuthSignals holds the signals used to detect auth walls.

type CaptureOpts

type CaptureOpts struct {
	ProxyURL      string
	BrowserPath   string
	Timeout       time.Duration
	WaitAfterLoad time.Duration
	Cookies       []string // name=value pairs to inject before navigation
	// Headful launches a visible Chrome window so the operator can
	// perform real-user interactions (save draft, add to cart, etc.)
	// while the capture runs. Default false — headless for CI/automated
	// discovery.
	Headful bool
}

CaptureOpts holds options for a browser capture session.

type CaptureResult

type CaptureResult struct {
	HAR          *HARLog
	DOMSnapshot  string
	RenderedHTML string
}

CaptureResult holds the output of a browser capture session.

type HAREntry

type HAREntry struct {
	Request  HARRequest  `json:"request"`
	Response HARResponse `json:"response"`
}

HAREntry represents a single HTTP request/response pair.

type HARLog

type HARLog struct {
	Entries []HAREntry `json:"entries"`
}

HARLog represents a simplified HAR log containing captured HTTP entries.

func FilterHAR

func FilterHAR(har *HARLog) *HARLog

FilterHAR returns a new HARLog with noise removed. The input is not mutated.

Stage 1: Keep only entries whose response content-type matches an allowed API type. Stage 2: Drop entries whose URL contains known analytics/tracking patterns. Stage 3: Deduplicate by Method + URL, keeping the first occurrence.

type HARRequest

type HARRequest struct {
	Method  string            `json:"method"`
	URL     string            `json:"url"`
	Headers map[string]string `json:"headers"`
	Body    string            `json:"body,omitempty"`
}

HARRequest represents an HTTP request.

type HARResponse

type HARResponse struct {
	Status      int               `json:"status"`
	StatusText  string            `json:"status_text"`
	ContentType string            `json:"content_type"`
	Headers     map[string]string `json:"headers"`
	Body        string            `json:"body,omitempty"`
}

HARResponse represents an HTTP response.

type RodBrowser

type RodBrowser struct {
	// contains filtered or unexported fields
}

RodBrowser implements the Service interface using CDP protocol. Supports two backends:

  • Lightpanda (preferred): 9x less memory, 11x faster, instant startup
  • Chromium via Rod launcher (fallback): full browser compatibility

When Lightpanda returns thin/empty HTML (SPA not rendered), the browser automatically falls back to Chromium for a second capture attempt. Domains that required Chromium fallback are recorded in ~/.hermai/spa_domains.txt so subsequent visits skip Lightpanda entirely (avoiding double-latency).

func NewRodBrowser

func NewRodBrowser(browserPath string) (*RodBrowser, error)

NewRodBrowser creates a browser instance. Connection priority:

  1. If cdpURL is set, connect to that CDP endpoint directly (Lightpanda or remote browser)
  2. If Lightpanda is running on default port 9222, connect to it
  3. Fall back to launching Chromium via Rod

func NewRodBrowserWithCDP

func NewRodBrowserWithCDP(cdpURL, browserPath string) (*RodBrowser, error)

NewRodBrowserWithCDP connects to an explicit CDP WebSocket URL. Use this for Lightpanda, remote browsers, or Browserless.io. browserPath is stored for Chromium fallback when the CDP backend returns thin HTML (SPA not rendered).

func (*RodBrowser) Backend

func (rb *RodBrowser) Backend() string

Backend returns which browser engine is in use ("lightpanda" or "chromium").

func (*RodBrowser) Capture

func (rb *RodBrowser) Capture(ctx context.Context, targetURL string, opts CaptureOpts) (*CaptureResult, error)

Capture navigates to the target URL, captures network traffic as HAR, and extracts a simplified DOM snapshot. Uses CDP protocol events for passive network observation. Works with both Lightpanda and Chromium backends.

When Lightpanda returns thin rendered HTML (SPA not rendered), Capture automatically retries with a temporary Chromium instance for full JavaScript execution. This ensures SPAs (React, Next.js, Vue) still work.

func (*RodBrowser) Close

func (rb *RodBrowser) Close() error

Close shuts down the browser and launcher (if any).

func (*RodBrowser) SetSPADomainsFile

func (rb *RodBrowser) SetSPADomainsFile(path string)

SetSPADomainsFile enables auto-learning of SPA domains that require Chromium. The file records domains where Lightpanda returned thin HTML. On subsequent visits to these domains, Lightpanda is skipped entirely (saves 5-10s).

type Service

type Service interface {
	Capture(ctx context.Context, targetURL string, opts CaptureOpts) (*CaptureResult, error)
	Close() error
}

Service defines the browser capture interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL