Skip to content

v3.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Jul 10:24
3b82f9b

[3.1.0] - 2026-07-11

Added

  • Live crawl-time ETA (on by default): a periodic log line projecting remaining time from the crawl's own
    throughput/discovery history, withheld until the frontier drains steadily. New SimpleCrawler.Core.Progress
    namespace; CLI --progress, --progressInterval, --progressConfirm.

Changed

  • Replaced the shared FIFO crawl frontier with a host-partitioned one
    (SimpleCrawler.Core.Scheduling.HostFrontier) to end cross-site head-of-line blocking: a single
    dispatcher spaces each host and hands workers only ready URLs, so a slow host no longer stalls other
    sites. Equally-ready hosts round-robin.
  • Updated Simple.Logging.Console to 2.0.0 and switched the CLI to the new truecolor AddRgbConsoleLogging()
    (AddConsoleLogging() still exists for ANSI); a warm Write is now allocation-free.
  • Normalized per-page log lines across backends (Response '{code}' from '{url}' / Error …, numeric code
    everywhere) and proxy references (via '{proxy}', 'direct connection' when none); ProxyInfo.ToString()
    emits a clean scheme://host:port.
  • Checkpointing now logs its activity (start line with target+interval, debug line per write, failures name
    the target); ICheckpointStore gained a Target property.

Fixed

  • JS DOM: closed three shim gaps that tripped SPA error boundaries mid-render. IntersectionObserverEntry is
    now a global carrying the standard entry fields on its prototype (the 'isIntersecting' in IntersectionObserverEntry.prototype support probe threw a ReferenceError); <canvas> is a real
    HTMLCanvasElement with reflected width/height and a no-op 2D context from getContext('2d')
    (animation libraries grabbing a context synchronously threw); and getComputedStyle returns a
    CSSStyleDeclaration whose properties read back "" by name or as direct properties (a direct .content
    read was undefined, so Elementor's getCurrentDeviceMode did undefined.replace(...)).