Inline-only provider

toDataUri() deliberately rides the same variant cache as url(): the encoded bytes are published to the cache, then read back and base64-wrapped. That write is what keeps placeholders cheap — img(placeholder: 'thumbhash') resolves a data URI on every render, and the cached variant turns every render after the first into a read instead of a full source decode. Concurrent generation is de-duplicated, and purge() covers inline variants like any other.

The consequence: a local provider needs a writable cache and a cachePublicUrl even when you only ever inline. If you genuinely never serve a variant URL — a provider wired solely for LQIP generation, or for inlining images into email HTML — give it an in-memory filesystem:

use Intervention\Image\ImageManager;
use League\Flysystem\Filesystem;
use League\Flysystem\InMemory\InMemoryFilesystemAdapter;
use Timber\Chainsaw\Provider\Intervention\InterventionProvider;

$inline = new InterventionProvider(
    sourceReader: $reader,
    cache: new Filesystem(new InMemoryFilesystemAdapter()),
    cachePublicUrl: '/unused', // nothing is emitted on the inline path
    manager: ImageManager::gd(),
);

The in-memory adapter keeps the per-process memo — repeated renders of the same placeholder stay cheap within the process — without touching disk, and no URL is ever built from cachePublicUrl when only toDataUri() runs.

Worth weighing first: if the same images are also rendered as URLs elsewhere, one provider with a real cache is the better wiring — the inline and URL paths then share a single cached variant instead of encoding twice.