Query Tooling
Devtools
In development, eight detectors report the mistakes that cost requests (duplicates, waterfalls, dead invalidations, refetch loops) and a panel shows the cache. Production builds resolve the entry to a stub.
Markdown version of this page, for assistants (Markdown for AI)
Note ./devtools is experimental: the API can still change in a minor release.
Stability per entry point: Entry points.
On this page
Setup
export const client = createClient({
transport: http({ base: '/' }),
modules: [
devtools({
thresholds: { duplicateMs: 2000, refetches: 20 }, // tighter or looser than the defaults
ignore: [listTeams, 'waterfall'], // endpoints or detectors to stay silent about
panel: true // Alt+Shift+Q opens and closes it
})
]
});The development export condition resolves the real entry; every other build gets a
stub of the same names (92 B gzip) with no detector, no panel and no message.
Findings
Each finding is printed once per id with an slq/<detector> code. Read them in
code, or assert them in tests with t.findings():
// What the detectors found so far, once per finding id; each carries an slq/<detector> code.
for (const finding of findings(client)) console.table(finding);
// The latest timeline records: requests, commits, invalidations, mutations (never a payload).
const last = timeline(client).slice(-20);Detectors
| Detector | Reports |
|---|---|
dead-invalidation | An invalidation matched no entry and names a tag no endpoint provided. |
duplicate-request | An entry sent again for mount or params right after a successful answer. |
waterfall | A request started right after the entry its params or when read had committed. |
unscoped | A scope: false endpoint whose data depends on the operator or region. |
access-in-when | A right written as a when condition: it pauses but never removes forbidden data. |
leaked-optimistic | An optimistic layer still applied long after its run succeeded. |
retry-storm | Many retries to one origin, or one entry failing again and again. |
refetch-loop | An entry requested again and again for causes other than poll and live. |
Detectors arm no timer: checks that wait for time to pass run on later events and when findings
are read. Silence an endpoint or a detector with ignore.
Thresholds
| Threshold | Default | Used by |
|---|---|---|
duplicateMs | 1000 ms | duplicate-request |
waterfallMs | 50 ms | waterfall |
optimisticMs | 10000 ms | leaked-optimistic |
windowMs | 10000 ms | retry-storm, refetch-loop: sliding window |
retries | 20 | retry-storm: retries to one origin |
failures | 3 | retry-storm: failed sequences of one entry |
refetches | 10 | refetch-loop: sends of one entry |
Timeline
timeline(client) returns the latest records of a ring buffer (buffer records, never a payload, a params object or an error body): requests, commits, errors, removals,
invalidations, observers and mutations. Requests and mutations also appear as Queue, Network, Commit,
Mutations and Invalidate tracks in the browser's Performance panel (timing, on by
default).
Panel
<!-- An application's own control for the devtools panel -->
<script lang="ts">
import { getClient } from '@svelte-lean/query';
import { openPanel } from '@svelte-lean/query/devtools';
const client = getClient();
</script>
<button type="button" onclick={() => openPanel(client)}>Inspect queries</button>- With
panel: true, Alt + Shift + Q opens and closes it ({ shortcut }changes the keys,falseremoves them and leavesopenPanel(client)); Escape closes it. - It is a non-modal
<dialog>in the top layer with five views: Entries (with a lazy view of the selected value), Tags, Causes, Timeline and Findings. - Its UI is loaded on first use; closed, it costs one
keydownlistener.