Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/streams-metadata - Universal stream transforms that detect MIME type and extract EXIF/IPTC/XMP image metadata via @suaveplan/streams BaseTransform
Universal stream transforms that detect MIME type and extract
EXIF/IPTC/XMP image metadata from buffered Uint8Array payloads. Three
composable transforms (MimeTransform, ExifTransform, and the wrapping
MetadataTransform) each extend BaseTransform from @suaveplan/streams
and expose a typed event surface through the inherited on/off API.
Documentation tree
- errors — Stable error registry for the
@suaveplan/streams-metadatapackage. Every failure surface produced byMimeTransform,…- errors — Stable error registry for the
@suaveplan/streams-metadatapackage. Every failure surface produced byMimeTransform,…
- errors — Stable error registry for the
- events — Declares the typed
StreamsMetadataEventsmap consumed by every transform in this package.BaseTransformfro…- events — Declares the typed
StreamsMetadataEventsmap consumed by every transform in this package.BaseTransformfro…
- events — Declares the typed
- exif —
ExifTransformis a universal stream transform that extractsImageMetadatavia@suaveplan/exif::readMetadata…- exif —
ExifTransformis a universal stream transform that extractsImageMetadatavia@suaveplan/exif::readMetadata…
- exif —
- metadata —
MetadataTransformis the high-level composing wrapper aroundMimeTransformandExifTransform. A single instance r…- metadata —
MetadataTransformis the high-level composing wrapper aroundMimeTransformandExifTransform. A single instance r…
- metadata —
- mime —
MimeTransformis a universal stream transform that decides the MIME type of a buffered binary payload and (in `e…- mime —
MimeTransformis a universal stream transform that decides the MIME type of a buffered binary payload and (in `e…
- mime —
- payload — Public type contract shared by every
@suaveplan/streams-metadatatransform. Callers and library code agree on the sha… - process-options — Defines the
ProcessOptionsshape accepted by every@suaveplan/streams-metadatatransform's `process(input, options?…
Install
bun add @suaveplan/streams-metadata
Quick start
import { MetadataTransform } from "@suaveplan/streams-metadata";
const transform = new MetadataTransform();
const result = await transform.process({ bytes: imageBytes, name: "photo.jpg" });
console.log(result.mime?.mimeType); // "image/jpeg"
console.log(result.exif?.width); // 1920
Manual composition
Use MimeTransform and ExifTransform separately when you need
fine-grained control over each stage or want to run only one of them:
import { ExifTransform, MimeTransform } from "@suaveplan/streams-metadata";
const mime = new MimeTransform();
const exif = new ExifTransform({ read: { skipXmp: true } });
mime.on("mime:detected", (r) => console.log("MIME:", r.mimeType, "(source:", r.source, ")"));
exif.on("exif:detected", (m) => console.log("Dimensions:", m.width, "x", m.height));
const afterMime = await mime.process({ bytes: imageBytes, name: "photo.jpg" });
const afterExif = await exif.process(afterMime);
Error handling
MetadataTransform catches errors from either child transform, emits
metadata:error with the thrown value, and returns the original input
reference so the pipeline continues. MimeTransform never throws for
unknown bytes — the fallback is application/octet-stream. ExifTransform
wraps every reader exception as ExifFailedError
(STREAMS_METADATA.EXIF_FAILED) preserving the original cause.
Modules
src/mime/mime.md— MIME detection from magic bytes and file extension.src/exif/exif.md— EXIF / IPTC / XMP image metadata extraction via@suaveplan/exif.src/metadata/metadata.md— composing wrapper around both transforms with event forwarding.src/events/events.md— fullStreamsMetadataEventsreference.src/errors/errors.md—StreamsMetadataError, factory subclasses, and theSTREAMS_METADATA_CODESregistry.src/types/payload.md—MetadataPayload,EnrichedPayload,MimeDetectionResult,MetadataMode.src/types/process-options.md— runtimeProcessOptionsshape (signal / clock / logger) accepted by every transform.