@suaveplan/storage-uri-plugin-bundle - Per-package bundle:// URI scheme plugin for @suaveplan/storage-uri. Universal; resolves bundle:/// against an injectable rootUrl via fetch on every read. Read-only StorageLike shim, HTTP Range support with 200/206/416 disambiguation, AbortSignal propagation, optional in-memory LRU, full OpenTelemetry surface.
Per-package bundle:// URI scheme for @suaveplan/storage-uri.
bundle://<package-slug>/<rel-path> lets a consuming package ship binary
assets — impulse responses, sample fonts, reference images, fixture
bundles — alongside its npm tarball and resolve them through the existing
storage-uri ecosystem. The plugin is universal: zero node:fs,
zero browser-only branches, every read goes through an injectable
FetchLike against new URL(encodedRelPath, rootUrl). file:, https:,
http:, data:, blob:, and bundler-virtual schemes all flow through
the same fetch surface.
Documentation tree
- abort —
abort.tsdeclares the two helpers every read path consumes to honour anAbortSignal:ensureNotAbortedshort-circu…- abort —
abort.tsdeclares the two helpers every read path consumes to honour anAbortSignal:ensureNotAbortedshort-circu…
- abort —
- cache —
cache.tsdeclares the optional in-memory LRU used by the storage shim when a caller passes `options.cache = { maxByte…- cache —
cache.tsdeclares the optional in-memory LRU used by the storage shim when a caller passes `options.cache = { maxByte…
- cache —
- error-codes —
error-codes.tsdeclares the canonical registry of every error code raised by@suaveplan/storage-uri-plugin-bundlea…- error-codes —
error-codes.tsdeclares the canonical registry of every error code raised by@suaveplan/storage-uri-plugin-bundlea…
- error-codes —
- factory —
factory.tsis the public entry point for@suaveplan/storage-uri-plugin-bundle.bundleUriPlugin(options)validates…- factory —
factory.tsis the public entry point for@suaveplan/storage-uri-plugin-bundle.bundleUriPlugin(options)validates…
- factory —
- node-fetch —
nodeFileFetchis a server-tierFetchLikethat closes a real gap in Node's globalfetch: undici (the engine backin…- node-fetch —
nodeFileFetchis a server-tierFetchLikethat closes a real gap in Node's globalfetch: undici (the engine backin…
- node-fetch —
- otel —
otel.tsexposes the tracer, meter, and instrument bag that every read path in@suaveplan/storage-uri-plugin-bundle…- otel —
otel.tsexposes the tracer, meter, and instrument bag that every read path in@suaveplan/storage-uri-plugin-bundle…
- otel —
- parse —
parse.tsenforces thebundle://<package-slug>/<rel-path>grammar declared indesign.md §1and rejects every malfo…- parse —
parse.tsenforces thebundle://<package-slug>/<rel-path>grammar declared indesign.md §1and rejects every malfo…
- parse —
- range —
range.tsimplements the building blocks the storage shim uses to issue HTTPRangerequests and disambiguate the thr…- range —
range.tsimplements the building blocks the storage shim uses to issue HTTPRangerequests and disambiguate the thr…
- range —
- storage-shim —
storage-shim.tsdeclaresBundleStorageShim, theStorageLikeadapter thebundle://URI plugin exposes. The class…- storage-shim.fetch —
storage-shim.fetch.tscarries the two cross-cutting helpers every storage-shim method uses:safeFetchdispatches an… - storage-shim.head —
storage-shim.head.tsimplements the two HEAD-routed methods of the bundle storage shim.performExistsreturns a boo… - storage-shim —
storage-shim.tsdeclaresBundleStorageShim, theStorageLikeadapter thebundle://URI plugin exposes. The class… - storage-shim.range —
storage-shim.range.tscarries the fullgetPartialpipeline: pre-fetch offset/length validation, the `Range: bytes=……
- storage-shim.fetch —
- streaming —
streaming.tsexposes the single helper the storage shim consumes from itscreateReadStreamimplementation: given a…- streaming —
streaming.tsexposes the single helper the storage shim consumes from itscreateReadStreamimplementation: given a…
- streaming —
- types —
plugin-options.schemas.tsdeclares the Zod schema that validatesBundleUriPluginOptionsat construction time. The s…- plugin-options.schemas —
plugin-options.schemas.tsdeclares the Zod schema that validatesBundleUriPluginOptionsat construction time. The s…
- plugin-options.schemas —
Modules
./error-codes/error-codes—BUNDLE_URI_CODES(9 codes) +BundleUriError../factory/factory—bundleUriPlugin(options)entry point../parse/parse—parse+buildwith three-pass traversal prevention../storage-shim/storage-shim—BundleStorageShim(StorageLike)../storage-shim/storage-shim.fetch—safeFetch+assertSuccess../storage-shim/storage-shim.head— HEAD-backedexists/getMetadata../storage-shim/storage-shim.range— Range pipeline with 206/200/416 disambiguation../range/range—validateRange,buildRangeHeader,sliceForRange../streaming/streaming—toReadableStream../abort/abort—ensureNotAborted+wrapAbortError../cache/cache—UriLruCache../otel/otel— meter + tracer wiring,recordOp, fallback counters../node-fetch— server-tier opt-inFetchLikefor Node consumers whoserootUrlis afile://URL (see Node users +file://roots).
Quick start — register one plugin per consuming package
import { createStorageUriResolver } from "@suaveplan/storage-uri";
import { bundleUriPlugin } from "@suaveplan/storage-uri-plugin-bundle";
const resolver = createStorageUriResolver({});
// In each consuming package's `register()`:
resolver.register(
bundleUriPlugin({
packageSlug: "audio-ir-room-plugin-club",
rootUrl: new URL("./", import.meta.url),
})
);
const bytes = await resolver.read(
"bundle://audio-ir-room-plugin-club/assets/club.wav"
);
Bundler composition — flatten assets to a CDN URL
Vite, esbuild, and webpack all rewrite new URL("./assets/x.wav", import.meta.url)
at build time. Register the plugin with a rootUrl pointing at the
flattened asset directory and the runtime fetch transparently lands on
the bundler-produced URL:
// Vite / esbuild / webpack
import assetsRoot from "./assets/?url"; // → flattened bundle URL
bundleUriPlugin({
packageSlug: "audio-ir-room-plugin-club",
rootUrl: assetsRoot, // bundler-rewritten string is fine
});
In production this becomes a real HTTPS URL — bundle:// still resolves
the relative path inside that root through fetch, and the OTel surface
classifies the root as root_kind="http".
Node users + file:// roots
Node's global fetch (undici, all releases through Node 24) does NOT
support file: URLs. If your rootUrl is a file:// URL and you are
running on Node, the default globalThis.fetch wiring will reject on
the first get. The package ships a dedicated server-tier adapter at
the ./node-fetch subpath that closes the gap:
import { bundleUriPlugin } from "@suaveplan/storage-uri-plugin-bundle";
import { nodeFileFetch } from "@suaveplan/storage-uri-plugin-bundle/node-fetch";
const plugin = bundleUriPlugin({
packageSlug: "audio-ir-room-plugin-club",
rootUrl: new URL("./assets/", import.meta.url),
fetch: nodeFileFetch, // ← required on Node when rootUrl is file://
});
nodeFileFetch reads file: URLs via node:fs/promises, returns a
real Response with content-length + last-modified, honours HEAD
and Range: bytes=<start>-<end> (including open-ended bytes=10-), and
threads init.signal into the underlying read. Any non-file: URL
falls through to globalThis.fetch, so a single adapter handles both
local-disk and CDN roots without branching at the call site.
Bun's native fetch already supports file: URLs — Bun consumers can
keep using the default globalThis.fetch wiring. The subpath import
exists so the package's default export stays universal-pure (no
node:* imports leak into browser, Cloudflare Workers, Deno, or React
Native builds).
Composition — front the plugin with storage-plugin-cache
import { cachedStorage } from "@suaveplan/storage-plugin-cache";
import { MemoryCache } from "@suaveplan/cache";
const cache = new MemoryCache<Uint8Array>();
const cached = cachedStorage(plugin.adapter, { cache, namespace: "bundle" });
Error codes
BUNDLE_URI.PACKAGE_MISMATCH, PATH_TRAVERSAL, READ_ONLY,
NOT_FOUND, INVALID_URI, FETCH_FAILED, RANGE_INVALID,
RANGE_UNSUPPORTED, ABORTED — all reachable from a real call site
exercised by the test suite.
OpenTelemetry
bundle_uri.op_duration_ms{op, root_kind, outcome}histogram.bundle_uri.reads_total{root_kind, outcome}counter.bundle_uri.errors_total{root_kind, code}counter.bundle_uri.range_fallback_total{root_kind}counter.bundle_uri.cache_hits_total{root_kind}/bundle_uri.cache_misses_total{root_kind}counters.- Per-op span on the
@suaveplan/storage-uri-plugin-bundletracer withbundle.package,bundle.rel_path(query-stripped + 256-char clip),bundle.root_kind(file | http | data | blob | other),bundle.outcomeattributes.
Inject a MeterProvider with setBundleUriMeterProvider(provider) then
resetInstruments() to rebind.