Class: RangeGate

bemap.RangeGate(optionsopt)

new RangeGate(optionsopt)

Optional resilience gate for tile reads: concurrency cap + per-attempt TTFB timeout with smart-abort semantics + retries with backoff. When inactive (`setActive(false)` or `?nogate`) it is a pure pass-through (raw fetch). Read live per request, so toggling takes effect without a reload.
Parameters:
Name Type Attributes Description
options Object <optional>
Properties
Name Type Attributes Default Description
concurrency Number <optional>
0 Max in-flight reads (0 = uncapped).
timeoutMs Number <optional>
3500 Per-attempt TTFB (pre-header) timeout (0 = none). Must stay ABOVE the Worker's ~3000 ms tile deadline so its 504 is received (and retried) instead of the socket being aborted just before it lands. Once headers arrive this timer is disarmed — see `bodyTimeoutMs`.
bodyTimeoutMs Number <optional>
20000 Post-header BODY safety cap (0 = none). Generous ON PURPOSE: physically aborting a streaming tile body poisons the browser's shared H2/H3 connection; tile bodies are small and normally finish in well under a second — this cap only guards a truly dead socket.
maxRetries Number <optional>
3 Retries on a transient failure (429/5xx/timeout/network); never on a caller cancel. 1 → 3 (2026-07 fix): a single retry left ~1 in 25 tiles permanently grey under pan bursts; three retries bring the residual to ~0.1 %.
retryBackoffMs Array.<Number> <optional>
[200,500,1000] Backoff (ms) before retries #1/#2/#3… (the last entry repeats) — gives a strained connection time to heal before the re-attempt.
active Boolean <optional>
true Whether the gate is engaged.
Since:
  • 2.0.0
Source:

Methods

isActive()

Source:

run(attemptFn, callerSignalopt) → {Promise}

Run one tile-read attempt through the gate. `attemptFn(signal, headersReceived)` must perform the whole read (fetch + body) and resolve/reject. SMART ABORT: `signal` is the gate's PRIVATE per-attempt `AbortController` signal — the TTFB timer and a caller (pan/zoom) cancel abort it ONLY until the attempt calls `headersReceived()` (do so the moment the response headers are in). From that point the socket is protected: the body drains to completion under the generous `bodyTimeoutMs` safety cap, and a caller cancel is honoured LOGICALLY once the attempt settles (reject `AbortError`, discard the result — bytes already warmed the browser cache). An `attemptFn` that never calls `headersReceived` keeps the legacy whole-attempt timeout. Retries (up to `maxRetries`, spaced by `retryBackoffMs`) apply to transient failures only — 429/5xx, a network `TypeError`, a timeout `AbortError` — and NEVER to a caller cancel. Each attempt takes its own concurrency slot (a retry re-queues at the back instead of squatting a permit across its backoff sleep).
Parameters:
Name Type Attributes Description
attemptFn function `function(signal, headersReceived) => Promise`
callerSignal AbortSignal <optional>
the pmtiles cancellation signal
Source:
Returns:
Type
Promise

setActive()

Toggle the gate live (no reload). Notifies subscribers. @public
Source:

subscribe()

Subscribe to active-state changes. @public @return {Function} unsubscribe
Source: