2.9 KiB
middleware
(no submodules)
Purpose
middleware.ts builds the DriveMiddleware registered on a Drive by driveCachePlugin. The middleware intercepts read(ctx, next) to short-circuit hot paths from the cache and to populate fresh entries on a miss. write and delete interceptions are delegated to middleware.invalidation. stat and list are pure passthroughs in this iteration.
A cache is a perf optimisation, not a correctness boundary. Every underlying cache failure (get rejection, set rejection, delete rejection) is captured into stats.errors and the OTel errors_total{namespace, op} counter — and is never propagated to the consumer.
Features
- Pre-aborted
AbortSignalshort-circuits the cache work and defers tonext()so the inner storage surfaces canonicalDRIVE.ABORTED. - Live
AbortSignalis forwarded tocache.getfor caches whosegetaccepts a signal. shouldCache(path, bytes)predicate gates population — defaults to a 16-MiB byte ceiling matchingdrive-mesh-protocol'sMAX_FRAME_BYTES.- Population enforces the byte ceiling defensively; an oversize entry raises a structured
DRIVE_CACHE.CACHE_TOO_LARGEinternally and is suppressed (counted onstats.errors). statandlistpass straight tonext()without touching the cache.
Usage: Basic
import { buildMiddleware } from "@suaveplan/drive-plugin-cache/middleware";
import { createMutableStats } from "@suaveplan/drive-plugin-cache/handle";
const stats = createMutableStats();
const mw = buildMiddleware({ cache, stats, namespace: "drive" });
drive.useMiddleware(mw);
Usage: Advanced
const mw = buildMiddleware({
cache,
stats,
namespace: "media",
invalidateOnWrite: true,
invalidateOnDelete: false,
shouldCache: (path, bytes) =>
path.endsWith(".mov") && bytes.byteLength <= 8 * 1024 * 1024,
maxEntryBytes: 8 * 1024 * 1024,
logger,
});
API Reference
| Export | Shape | Description |
|---|---|---|
BuildMiddlewareArgs |
{ cache; stats; namespace?; invalidateOnWrite?; invalidateOnDelete?; shouldCache?; maxEntryBytes?; logger? } |
Constructor bag. |
buildMiddleware(args) |
(BuildMiddlewareArgs) => DriveMiddleware |
Returns the full DriveMiddleware (read + write + delete + stat + list). |
Implementation Notes
The cache key is computed as ${namespace}::${ctx.path}. The :: separator avoids accidental collision with paths that already contain /. Population happens after next() resolves — i.e. only when the inner storage actually produced bytes — so a thrown next() cannot poison the cache. Symmetrically, invalidation happens after a successful write/delete next(). The optimistic alternative (delete before next()) opens a race window where a concurrent read could repopulate stale bytes between the cache delete and the storage write.