8.8 KiB
OpenSpec Change: enterprise-mime
- Change ID: enterprise-mime
- Package:
@suaveplan/mime - Category: universal
- Target path:
packages/universal/mime - Status: PROPOSED
- Date: 2026-04-19
- Reference spec:
/mnt/s/web/suaveplan/enterprise/mime.md
Summary
Greenfield implementation of @suaveplan/mime for the genesis branch. This package delivers structured MIME-type detection, parsing, and registry at enterprise quality: magic-byte sniffing via a compiled trie over a signature table, RFC 7231 Content-Type parsing (quoted-string parameters, charset normalisation, round-trip serialisation), a curated IANA-sourced type database with extension↔type↔category lookups, charset sniffing (BOM, HTML meta, XML declaration), an extensible signature registry, structured errors, Zod schemas, OTel instrumentation, property-based tests, and benchmarks. Zero browser/Node/React dependencies — pure TypeScript runnable in Bun, Node, and browser.
Current-state audit (genesis)
The package does not exist on genesis yet — this is a fresh build.
Available workspace deps on genesis
| Package | Available |
|---|---|
@suaveplan/error |
✅ |
@suaveplan/types |
✅ |
@suaveplan/logger |
✅ |
@suaveplan/opentelemetry |
❌ not yet built — use @opentelemetry/api directly |
@suaveplan/schema-registry |
❌ not yet built — export Zod schemas directly |
@suaveplan/streams |
❌ not yet built — detectFromStream is a thin wrapper over detectFromMagicBytes with AbortSignal |
External deps (via catalog):
zod→catalog:forms@opentelemetry/api→catalog:observabilitytslib→catalog:build
Dev deps (via catalog):
vitest,@vitest/coverage-istanbul→catalog:testingfast-check→catalog:testingmitata→catalog:testing
Preserved public API surface (from main branch)
Charset
type BomDetection— detected charset from a BOM prefixsniffBom(bytes)→BomDetection | null— detect charset from BOMsniffHtmlMeta(bytes)→string | null— detect charset from HTML<meta>tagsniffXmlDecl(bytes)→string | null— detect charset from XML declaration
Content-type
contentTypeEquals(a, b)→boolean— structural equality ignoring parameter ordercontentTypeMatches(actual, pattern)→boolean— wildcard*subtype matchingformatContentType(parsed)→string— canonical round-trip serialisationtype MediaType—{ type: string; subtype: string }type ParsedContentType—{ mediaType: MediaType; parameters: Record<string, string> }parseContentType(value)→ParsedContentType— RFC 7231 parser with quoted-string support
Database
BUILTIN_DB— the built-in curated IANA-sourced registry (read-only reference)getEntryByExtension(ext)→MimeEntry | undefinedgetMimeEntry(mimeType)→MimeEntry | undefinedlistMimeEntries()→MimeEntry[]type MimeCategory—'image' | 'audio' | 'video' | 'text' | 'application' | 'font' | 'model' | 'message' | 'multipart' | 'chemical'type MimeEntry—{ mimeType: string; category: MimeCategory; extensions: string[]; compressible?: boolean; charset?: string }registerMimeEntry(entry)→void— add or override an entry at runtime
Detection
type ContentTypeDetectionResult— detection result sourced from a Content-Type headertype DetectInput—{ bytes?: Uint8Array; extension?: string; contentType?: string; signal?: AbortSignal }type DetectResult— union ofMagicBytesResult | ExtensionDetectionResult | ContentTypeDetectionResult | StreamDetectionResulttype DetectSource—'magic' | 'extension' | 'content-type' | 'stream'detect(input)→Promise<DetectResult>— unified detection: tries magic bytes first, then extension, then Content-Type headerdetectAllFromMagicBytes(bytes)→MagicBytesResult[]— all matching signatures for a bufferdetectFromContentType(contentType)→ContentTypeDetectionResult— detection from parsed header alonedetectFromExtension(ext)→ExtensionDetectionResult— detection via extension lookupdetectFromMagicBytes(bytes)→MagicBytesResult— best-match detection from bufferdetectFromStream(stream, opts?)→Promise<StreamDetectionResult>— thin AbortSignal wrapper overdetectFromMagicBytes; defers full streaming integration until@suaveplan/streamsshipstype ExtensionDetectionResult— detection result sourced from a file extensiontype MagicBytesResult— detection result sourced from magic bytesregisterSignature(sig)→void— add a custom signature to the trie at runtimetype Signature—{ mimeType: string; bytes: Uint8Array; offset?: number; mask?: Uint8Array }type StreamDetectionResult— detection result sourced from a readable stream
Errors
MIME_ERROR_METADATA— error code metadata map for@suaveplan/errordefineCodestype MimeErrorCode— union of allMIME.*code stringsregisterMimeErrorCodes()— registers all MIME error codes with the process-wide registryInsufficientBytesErrorextendsMimeError— thrown when the buffer is too short for magic-byte detectiontype InsufficientBytesErrorCodetype InsufficientBytesErrorContext—{ needed: number; got: number }type InsufficientBytesErrorOptionsInvalidContentTypeErrorextendsMimeError— thrown when a Content-Type string fails to parsetype InvalidContentTypeErrorCodetype InvalidContentTypeErrorContext—{ raw: string }type InvalidContentTypeErrorOptionsUnknownMimeTypeErrorextendsMimeError— thrown when a MIME type string has no registry entrytype UnknownMimeTypeErrorCodetype UnknownMimeTypeErrorContext—{ mimeType: string }type UnknownMimeTypeErrorOptions
Reverse lookups (main branch additions to preserve)
toAllExtensions(mimeType)→string[]— all extensions mapped to a MIME typetoCategory(mimeType)→MimeCategory | undefined— category lookup by MIME type stringtoDefaultExtension(mimeType)→string | undefined— canonical primary extension
Legacy
getMimeType(ext)→string | undefined— simple extension-to-mime-type lookup (legacy shim; retained for API surface completeness)
New additions for genesis
Structured errors
MimeErrorbase class extendsSuaveplanErrorwith codes under theMIME.*namespace- Error codes:
MIME.PARSE_ERROR,MIME.INSUFFICIENT_BYTES,MIME.UNKNOWN_SIGNATURE,MIME.UNKNOWN_TYPE,MIME.INVALID_CONTENT_TYPE InsufficientBytesError,InvalidContentTypeError,UnknownMimeTypeError,ParseError,UnknownSignatureErrorall extendMimeError- Error codes registered via side-effect
import "./error-codes.js"insrc/index.ts
Zod schemas
ParsedContentTypeSchema— validatesParsedContentTypeat the boundaryMimeEntrySchema— validatesMimeEntryandMimeCategorySignatureSchema— validates aSignaturebefore insertion into the trieDetectResultSchema— discriminated union validator forDetectResultDetectInputSchema— validatesDetectInputoptions
OTel instrumentation (via @opentelemetry/api, no-op without exporter)
- Counter
mime.detect.total— bysourcelabel (magic/extension/content-type/stream) - Histogram
mime.detect.duration_ms— perdetect()call - Counter
mime.parse.total— byoutcomelabel (success/error)
detectFromStream — deferred streaming, interim shim
detectFromStream is exported and typed as in the main branch but is implemented as a thin wrapper that reads the first chunk from the provided async iterable (or ReadableStream) with an AbortSignal and delegates to detectFromMagicBytes. Full streaming integration is deferred until @suaveplan/streams ships.
Property-based tests (fast-check)
parseContentType → formatContentTyperound-trip: for any valid Content-Type string,formatContentType(parseContentType(s))parses back to the sameParsedContentType- Magic-byte detection:
detectFromMagicBytes(bytes)always returns a result or throwsInsufficientBytesError— never throws any other error class - Registry round-trip: any entry registered via
registerMimeEntry(e)is immediately retrievable viagetMimeEntry(e.mimeType)with identical shape
Benchmarks (mitata)
parseContentType— 10 000 iterations over a representative set of realistic Content-Type stringsdetectfromUint8Array— 10 000 iterations with a 4 KB buffer covering a variety of magic-byte signaturesgetMimeEntrylookup — 100 000 iterations over the built-in database
Impact
- Adds one new package:
packages/universal/mime - Adds one new spec capability:
mime - No existing package consumers on genesis yet