Files
2026-05-27 23:29:53 +01:00

5.1 KiB

Design: enterprise-media

Module layout

packages/foundation/data/media/src/
  detection/       detectMediaType, detectSignature, detectMediaTypeFromName,
                   inferMimeFromSignature, defaultMimeForType
  metadata/        getMetadata, getMetadataAsync, MetadataOptions
  validation/      validateMedia, validateMediaAsync, assertValidMedia,
                   ValidateOptions
  signatures/      BUILTIN_SIGNATURES, SignatureRegistry,
                   defaultSignatureRegistry
  errors/          MEDIA_CODES, MEDIA_ERROR_METADATA, MediaError, asMediaError
  observability/   createMediaObservability + counter / histogram types
  types/           MediaType, MediaSignature, MediaMetadata, MediaConstraints,
                   MediaResult, MediaMetadataExtractor + Zod schemas
  index.ts         root barrel — explicit named re-exports

Every feature folder is the canonical four-file pattern (<name>.ts, <name>.test.ts, <name>.md, index.ts). Co-located .md docs cover purpose, features, basic + advanced usage, API reference, and implementation notes.

Detection pipeline

  1. detectMediaType(input, opts?) resolves opts.registry ?? defaultSignatureRegistry and delegates to registry.detect(input).
  2. detectSignature(input, opts?) returns the matched MediaSignature | null so consumers can route on the label (PNG / JPEG / MP4 / …) and not just the coarse MediaType.
  3. detectMediaTypeFromName(filename, opts?) calls @suaveplan/mime.getMimeType and buckets the result by top-level type (image/, video/, audio/).
  4. inferMimeFromSignature(sig) maps the matched signature label to a canonical MIME, falling back to defaultMimeForType(sig.type) when no per-label mapping exists.

SignatureRegistry exposes register, unregister, list, match, and detect. register rejects empty byte arrays (MEDIA.INVALID_SIGNATURE), non-byte values (MEDIA.INVALID_SIGNATURE), and duplicate labels (MEDIA.DUPLICATE_SIGNATURE). The built-in list orders longer / more- specific signatures first so the first match wins.

Metadata pipeline

getMetadata builds the base bundle ({ type, mimeType, size, signatureLabel }) in a private helper. getMetadataAsync accepts an optional MediaMetadataExtractor that receives (input, base) and returns Partial<MediaMetadata>; the helper merges the partial over the base. Extractor exceptions are wrapped in MediaError(MEDIA.METADATA_EXTRACTOR_FAILED) with the original error chained.

MIME resolution prefers the explicit filename field (via getMimeType) and falls back to inferMimeFromSignature. The base bundle exposes signatureLabel so downstream extractors can route on the exact format.

Validation pipeline

validateMedia runs:

  1. MediaConstraintsSchema.safeParse(constraints) (unless caller passes skipConstraintValidation: true). Failure raises MediaError(MEDIA.INVALID_CONSTRAINTS).
  2. Empty-input guard: zero-byte input raises MediaError(MEDIA.EMPTY_INPUT).
  3. getMetadata(input, opts) to build the bundle.
  4. checkConstraints(metadata, constraints) to populate the error array (size floors / ceilings, type / MIME allowlists, width / height ceilings + floors, duration ceiling).

validateMediaAsync runs the same pipeline but calls getMetadataAsync and, after constraint checks, runs constraints.predicate(metadata, input). Predicate return values:

  • null / undefined — pass.
  • string — push onto the errors array.
  • thrown — wrapped in MediaError(MEDIA.PREDICATE_FAILED).

assertValidMedia calls the sync variant and throws MediaError(MEDIA.VALIDATION_FAILED) if any error is reported, incrementing the media_error_total counter with { code }.

Observability

createMediaObservability(opts?) builds the bundle. If opts.observability is supplied it short-circuits. Otherwise the function resolves meter and tracer from opts or the global @opentelemetry/api providers and constructs counters / histograms via the helpers in @suaveplan/opentelemetry. Every public entrypoint constructs a default bundle when none is supplied so calls always emit telemetry without requiring caller-side wiring.

Error model

MEDIA_CODES is built via defineCodes("MEDIA", [...] as const) so the namespace and value strings line up with the rest of the monorepo. MEDIA_ERROR_METADATA is Object.freeze'd at module load. MediaError extends SuaveplanError<MediaErrorCode> and exposes a .metadata getter that pulls the matching record. asMediaError(code, cause, fallback) lifts unknown thrown values, preserving the original error as .cause when it's already an Error instance.

Why split into seven feature folders

The package is small (~700 LOC after the enterprise rewrite) but each module owns a distinct concern: detection / metadata / validation are end-user surfaces; signatures / errors / observability are infrastructure shared across the three; types holds the data contracts. The split keeps <file>.ts under the 300-line hard limit and lets tree-shake-sensitive consumers deep-import via the subpath exports without dragging in the full bundle.