Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
# 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.

View File

@@ -0,0 +1,89 @@
# Change: enterprise-media
- **Package**: `@suaveplan/media`
- **Status**: PROPOSED
- **Design**: ./design.md
- **Spec delta**: ./specs/media/spec.md
- **Upstream**: `/mnt/s/web/suaveplan/packages/universal/media` (1.1.0)
- **Enterprise audit**: `/mnt/s/web/suaveplan/enterprise/media.md`
## Why
Genesis is migrating `@suaveplan/media` from the legacy
`packages/universal/media/` checkout into the canonical
`packages/foundation/data/media/` location alongside the already-shipped
`@suaveplan/mime`. The upstream package shipped at 1.1.0 as a ~140-line
universal-tier facade over four functions — `detectMediaType` (magic
bytes), `detectMediaTypeFromName` (MIME lookup), `getMetadata`, and
`validateMedia`. The enterprise audit (`enterprise/media.md`) flagged
the gaps shared by every pre-enterprise package:
1. Hand-rolled error strings — no `@suaveplan/error` integration, no
stable codes, no programmatic discrimination.
2. No Zod validation of `MediaConstraints` — malformed input silently
passes through.
3. No OpenTelemetry instrumentation — production cannot measure
detection / metadata / validation volume, latency, or error rate.
4. Magic-byte signatures hard-coded inside the implementation — no
extension point for downstream packages to add formats like AVIF,
HEIC, or M4A.
5. No async metadata extractor hook — width / height / duration / codec
extraction has to happen outside the package.
6. No custom-predicate constraint — non-trivial business rules cannot
be expressed.
7. No throwing assert variant for guard sites.
8. No filename-MIME refinement when both bytes and filename are
available.
9. No `signatureLabel` surfacing — consumers cannot route on the exact
matched format.
The greenfield rewrite addresses every gap while preserving every
upstream public symbol so downstream consumers continue to compile
against the same import paths.
## What changes
- **Add**: `@suaveplan/media` at version `0.1.0` under
`packages/foundation/data/media/` with full enterprise surface — typed
errors via `@suaveplan/error`, OTel counters + histograms,
Zod-validated constraints, pluggable `SignatureRegistry`, async
metadata extractor hook, custom predicate support, async + assert
validation variants, filename + bytes MIME resolution, canonical MIME
inference from signature label.
- **Add**: error-code namespace `MEDIA.*` with eight stable codes
(`EMPTY_INPUT`, `INVALID_CONSTRAINTS`, `VALIDATION_FAILED`,
`UNSUPPORTED_TYPE`, `PREDICATE_FAILED`, `DUPLICATE_SIGNATURE`,
`METADATA_EXTRACTOR_FAILED`, `INVALID_SIGNATURE`).
- **Add**: OTel instruments — counters `media_detect_total`,
`media_metadata_total`, `media_validate_total`, `media_error_total`
and histograms `media_op_latency_ms`, `media_input_size_bytes`.
- **Add**: subpath exports per feature module
(`./detection/detection`, `./metadata/metadata`,
`./validation/validation`, `./errors/errors`,
`./observability/observability`, `./signatures/signatures`,
`./types`).
- **Add**: `media` to the `data` plugin in
`scripts/folder-reorg/assignment.yml`.
## Impact
### Affected dependents
`bunx turbo ls --filter=...@suaveplan/media` — empty (media is a leaf
migration; no current genesis package depends on it).
## Parity Checklist
| Capability | Upstream | Migrated | Notes |
| ------------------------------------------------------------------- | -------- | -------- | -------------------------------------------------------------------------------- |
| `detectMediaType(bytes)` | yes | yes | Now routes through pluggable `SignatureRegistry`. |
| `detectMediaTypeFromName(filename)` | yes | yes | Same MIME-bucket semantics; emits counter + latency. |
| `getMetadata(bytes, filename?)` | yes | yes | Adds `signatureLabel`; MIME refines to filename when present. |
| `validateMedia(bytes, constraints, filename?)` | yes | yes | Now Zod-validated; reports MIME / minSize / minWidth / minHeight / maxDuration. |
| `MediaType` / `MediaMetadata` / `MediaConstraints` / `MediaResult` | yes | yes | Preserved; `MediaConstraints` extended with new fields. |
| Pluggable signatures | no | yes | New `SignatureRegistry` class + `defaultSignatureRegistry`. |
| Async metadata extractor | no | yes | New `getMetadataAsync` + `MediaMetadataExtractor` hook. |
| Async validation predicate | no | yes | New `validateMediaAsync` runs `constraints.predicate`. |
| Throwing assert variant | no | yes | New `assertValidMedia`. |
| Typed errors | no | yes | `MediaError` + `MEDIA_CODES` + per-code metadata. |
| OTel instrumentation | no | yes | Four counters + two histograms. |

View File

@@ -0,0 +1,357 @@
<!-- markdownlint-disable MD024 -->
# Capability Spec Delta: media (media)
**Package**: `@suaveplan/media`
**Status**: PROPOSED
> Every requirement below carries a `**Verified by:**` line at authoring time. No exceptions.
## ADDED Requirements
### Requirement: Stable error code registry
The package SHALL expose a `MEDIA_CODES` constant created via
`defineCodes("MEDIA", [...] as const)` containing exactly eight stable codes:
`EMPTY_INPUT`, `INVALID_CONSTRAINTS`, `VALIDATION_FAILED`, `UNSUPPORTED_TYPE`,
`PREDICATE_FAILED`, `DUPLICATE_SIGNATURE`, `METADATA_EXTRACTOR_FAILED`,
`INVALID_SIGNATURE`. Each code MUST have a metadata record (`httpStatus`,
`retryable`, `severity`, `description`) accessible via `MEDIA_ERROR_METADATA`.
#### Scenario: registry shape is frozen
- **WHEN** a consumer reads `MEDIA_CODES`
- **THEN** the returned object MUST contain all eight expected keys and MUST
be `Object.isFrozen`.
#### Scenario: every code is namespaced
- **WHEN** a consumer iterates `Object.values(MEDIA_CODES)`
- **THEN** every value MUST start with the `MEDIA.` namespace prefix.
**Verified by:** `src/errors/errors.test.ts::"contains all eight stable codes"` AND `src/errors/errors.test.ts::"registry is frozen"` AND `src/errors/errors.test.ts::"codes carry MEDIA namespace prefix"`
---
### Requirement: MediaError extends SuaveplanError
The package SHALL export `MediaError extends SuaveplanError<MediaErrorCode>`.
Constructing `new MediaError(MEDIA_CODES.EMPTY_INPUT, "msg")` MUST yield an
instance whose `.code === "MEDIA.EMPTY_INPUT"`, whose `.message === "msg"`,
and which satisfies both `instanceof MediaError` and `instanceof Error`. The
class MUST expose a `.metadata` getter returning the matching record from
`MEDIA_ERROR_METADATA`.
#### Scenario: round-trips through cause chain
- **WHEN** a `MediaError` is constructed with `cause: nativeErr`
- **THEN** `error.cause` MUST return the original native error and
`error.code` MUST preserve the namespaced code.
#### Scenario: metadata getter resolves code
- **WHEN** a consumer reads `new MediaError(MEDIA_CODES.UNSUPPORTED_TYPE,
"x").metadata`
- **THEN** the returned record MUST report `httpStatus: 415` and
`severity: "warning"`.
**Verified by:** `src/errors/errors.test.ts::"constructs with code, message, instanceof Error"` AND `src/errors/errors.test.ts::"preserves cause through chain"` AND `src/errors/errors.test.ts::"exposes metadata via getter"`
---
### Requirement: asMediaError lift helper
The package SHALL expose `asMediaError(code, cause, fallback)` that wraps an
unknown thrown value into a `MediaError`. When `cause instanceof Error` and
its message is non-empty, the wrapped error's `.message` MUST equal the
cause's message; otherwise it MUST equal the supplied `fallback`.
`error.cause` MUST be an `Error` instance regardless of the cause's original
shape.
#### Scenario: preserves Error message and cause
- **WHEN** `asMediaError(MEDIA_CODES.PREDICATE_FAILED, new Error("root"),
"fb")` is invoked
- **THEN** `.message` MUST be `"root"` and `.cause` MUST be the original
Error.
#### Scenario: falls back to default for non-Error cause
- **WHEN** `asMediaError(MEDIA_CODES.PREDICATE_FAILED, "scalar", "fb")` is
invoked
- **THEN** `.message` MUST be `"fb"` and `.cause` MUST be a synthesised
Error whose message is `"scalar"`.
**Verified by:** `src/errors/errors.test.ts::"preserves Error cause when wrapping"` AND `src/errors/errors.test.ts::"falls back to default message when cause has none"`
---
### Requirement: Pluggable signature registry
The package SHALL expose a `SignatureRegistry` class with `register`,
`unregister`, `list`, `match`, and `detect` methods. `BUILTIN_SIGNATURES`
MUST be a frozen array covering at minimum PNG, JPEG, GIF, BMP, WEBP, RIFF,
MP4/MOV, WebM/MKV, MP3 (ID3 + sync), FLAC, and OGG. A process-wide
`defaultSignatureRegistry` MUST be exposed, seeded with `BUILTIN_SIGNATURES`.
#### Scenario: built-in registry detects PNG
- **WHEN** `defaultSignatureRegistry.detect(new Uint8Array([0x89, 0x50,
0x4e, 0x47, 0x00]))` is invoked
- **THEN** the result MUST be `"image"`.
#### Scenario: signature offset is honoured
- **WHEN** the registry is asked to detect MP4 bytes whose `ftyp` marker
lives at offset 4
- **THEN** detection MUST return `"video"`.
#### Scenario: register rejects duplicate label
- **WHEN** a caller registers a second signature whose `label` matches an
existing entry
- **THEN** a `MediaError` with code `MEDIA.DUPLICATE_SIGNATURE` MUST be
thrown.
#### Scenario: register rejects empty bytes
- **WHEN** a caller registers a signature with `bytes: []`
- **THEN** a `MediaError` with code `MEDIA.INVALID_SIGNATURE` MUST be
thrown.
#### Scenario: register rejects non-byte values
- **WHEN** a caller registers a signature whose `bytes` array contains a
value outside `[0, 0xff]` or a non-integer
- **THEN** a `MediaError` with code `MEDIA.INVALID_SIGNATURE` MUST be
thrown.
#### Scenario: unregister removes by label
- **WHEN** a caller invokes `unregister("PNG")`
- **THEN** the method MUST return `true` and subsequent `detect` of PNG
bytes MUST return `"unknown"`.
**Verified by:** `src/signatures/signatures.test.ts::"detects PNG via default registry"` AND `src/signatures/signatures.test.ts::"honours non-zero offset (MP4 ftyp)"` AND `src/signatures/signatures.test.ts::"rejects duplicate label"` AND `src/signatures/signatures.test.ts::"register rejects empty byte array"` AND `src/signatures/signatures.test.ts::"register rejects non-byte values"` AND `src/signatures/signatures.test.ts::"unregister removes signature and returns true"`
---
### Requirement: Byte and filename detection
The package SHALL expose `detectMediaType(input, opts?)`,
`detectSignature(input, opts?)`, and `detectMediaTypeFromName(filename,
opts?)`. The bytes-based helpers MUST delegate to
`opts.registry ?? defaultSignatureRegistry`. The filename helper MUST call
`getMimeType` from `@suaveplan/mime` and bucket the result by top-level
type prefix (`image/`, `video/`, `audio/`).
#### Scenario: PNG bytes route to image
- **WHEN** `detectMediaType` is invoked with PNG magic bytes
- **THEN** the result MUST be `"image"`.
#### Scenario: empty input is detected as unknown
- **WHEN** `detectMediaType(new Uint8Array([]))` is invoked
- **THEN** the result MUST be `"unknown"`.
#### Scenario: filename .mp4 routes to video
- **WHEN** `detectMediaTypeFromName("clip.mp4")` is invoked
- **THEN** the result MUST be `"video"`.
**Verified by:** `src/detection/detection.test.ts::"detects PNG from magic bytes"` AND `src/detection/detection.test.ts::"returns unknown for empty input"` AND `src/detection/detection.test.ts::"detects video from .mp4 filename"`
---
### Requirement: Canonical MIME inference
The package SHALL expose `inferMimeFromSignature(sig)` and
`defaultMimeForType(type)`. `inferMimeFromSignature` MUST return the
canonical MIME for each built-in label (PNG → `image/png`, JPEG →
`image/jpeg`, MP4/MOV → `video/mp4`, WebM/MKV → `video/webm`, FLAC →
`audio/flac`, OGG → `audio/ogg`, MP3-ID3 / MP3-sync → `audio/mpeg`). For
unknown labels it MUST fall back to `defaultMimeForType(sig.type)`. For a
`null` signature it MUST return `"application/octet-stream"`.
#### Scenario: PNG signature maps to image/png
- **WHEN** `inferMimeFromSignature` is called with a PNG signature record
- **THEN** the result MUST be `"image/png"`.
#### Scenario: null signature falls back to octet-stream
- **WHEN** `inferMimeFromSignature(null)` is invoked
- **THEN** the result MUST be `"application/octet-stream"`.
**Verified by:** `src/detection/detection.test.ts::"returns canonical MIME for PNG signature"` AND `src/detection/detection.test.ts::"returns octet-stream for null signature"`
---
### Requirement: Metadata extraction with extractor hook
The package SHALL expose `getMetadata(input, opts?)` and
`getMetadataAsync(input, opts?)`. Both MUST return a `MediaMetadata` bundle
populated with `type`, `mimeType`, `size`, and (when a signature matched)
`signatureLabel`. When `opts.filename` is supplied, the MIME MUST be
resolved via `getMimeType(filename)`. The async variant MUST accept a
`MediaMetadataExtractor` and merge its return value over the base bundle.
#### Scenario: getMetadata reports type, mime, size, label
- **WHEN** `getMetadata(pngBytes, { filename: "x.png" })` is invoked
- **THEN** the returned bundle MUST satisfy `type === "image"`,
`mimeType === "image/png"`, `size === pngBytes.byteLength`,
`signatureLabel === "PNG"`.
#### Scenario: extractor merges async fields
- **WHEN** `getMetadataAsync` is invoked with an extractor that returns
`{ width: 100, height: 50 }`
- **THEN** the returned bundle MUST satisfy `width === 100` and
`height === 50`.
#### Scenario: extractor exception is wrapped
- **WHEN** the supplied extractor throws
- **THEN** `getMetadataAsync` MUST reject with a `MediaError` whose code
is `MEDIA.METADATA_EXTRACTOR_FAILED`, preserving the original error as
`.cause`.
**Verified by:** `src/metadata/metadata.test.ts::"returns type, mime, size, label for PNG bytes"` AND `src/metadata/metadata.test.ts::"merges extractor output"` AND `src/metadata/metadata.test.ts::"wraps extractor error in MediaError"`
---
### Requirement: Zod-validated constraints
`MediaConstraintsSchema` SHALL validate every constraint field. Malformed
constraints supplied to `validateMedia` or `validateMediaAsync` MUST cause
the call to throw `MediaError(MEDIA.INVALID_CONSTRAINTS)` unless the caller
opts out via `skipConstraintValidation: true`.
#### Scenario: negative maxSize is rejected
- **WHEN** `validateMedia(input, { maxSize: -1 })` is invoked without
`skipConstraintValidation`
- **THEN** a `MediaError` with code `MEDIA.INVALID_CONSTRAINTS` MUST be
thrown.
#### Scenario: skipConstraintValidation bypasses Zod
- **WHEN** `validateMedia(input, badConstraints, { skipConstraintValidation:
true })` is invoked
- **THEN** the call MUST NOT throw `MEDIA.INVALID_CONSTRAINTS`.
**Verified by:** `src/validation/validation.test.ts::"throws INVALID_CONSTRAINTS for malformed input"` AND `src/validation/validation.test.ts::"skips Zod check when skipConstraintValidation: true"`
---
### Requirement: Synchronous validation
`validateMedia(input, constraints, opts?)` SHALL run the empty-input guard,
build the metadata bundle, and apply every constraint check
(`minSize`, `maxSize`, `allowedTypes`, `allowedMimeTypes`, `maxWidth`,
`minWidth`, `maxHeight`, `minHeight`, `maxDuration`). It MUST return a
`MediaResult` whose `valid` flag is `errors.length === 0`. Empty input MUST
throw `MediaError(MEDIA.EMPTY_INPUT)`.
#### Scenario: compliant input returns valid result
- **WHEN** `validateMedia(pngBytes, { maxSize: 1024, allowedTypes:
["image"] })` is invoked
- **THEN** the result MUST satisfy `valid === true` and `errors.length ===
0`.
#### Scenario: empty input throws MEDIA.EMPTY_INPUT
- **WHEN** `validateMedia(new Uint8Array([]), {})` is invoked
- **THEN** a `MediaError` with code `MEDIA.EMPTY_INPUT` MUST be thrown.
#### Scenario: failures are reported per rule
- **WHEN** `validateMedia(pngBytes, { allowedTypes: ["video"],
allowedMimeTypes: ["image/jpeg"] })` is invoked
- **THEN** `errors` MUST contain entries for both the unsupported type and
unsupported MIME.
**Verified by:** `src/validation/validation.test.ts::"passes when all constraints met"` AND `src/validation/validation.test.ts::"rejects empty input with MediaError"` AND `src/validation/validation.test.ts::"fails when type not in allowedTypes"` AND `src/validation/validation.test.ts::"fails when MIME not in allowedMimeTypes"`
---
### Requirement: Asynchronous validation with predicate
`validateMediaAsync` SHALL behave identically to `validateMedia` but MUST
also run `constraints.predicate(metadata, input)` when present. A `string`
return value MUST be appended to the `errors` array. A `null` /
`undefined` return MUST pass. A thrown exception MUST surface as
`MediaError(MEDIA.PREDICATE_FAILED)` with the original error chained.
#### Scenario: predicate returning string contributes error
- **WHEN** `validateMediaAsync(input, { predicate: () => "rule failed" })`
is invoked
- **THEN** the result MUST satisfy `valid === false` and `errors` MUST
include `"rule failed"`.
#### Scenario: predicate exception wraps in MEDIA.PREDICATE_FAILED
- **WHEN** the supplied predicate throws
- **THEN** the call MUST reject with `MediaError(MEDIA.PREDICATE_FAILED)`,
preserving the original error as `.cause`.
**Verified by:** `src/validation/validation.test.ts::"runs predicate and reports its error string"` AND `src/validation/validation.test.ts::"predicate throwing yields PREDICATE_FAILED"`
---
### Requirement: assertValidMedia throwing variant
`assertValidMedia(input, constraints, opts?)` SHALL invoke `validateMedia`
and return the resulting `MediaMetadata` when `result.valid === true`. When
any error is reported it MUST throw
`MediaError(MEDIA.VALIDATION_FAILED)` whose message contains the joined
errors.
#### Scenario: returns metadata on success
- **WHEN** `assertValidMedia(pngBytes, { allowedTypes: ["image"] })` is
invoked
- **THEN** the returned bundle's `type` MUST be `"image"`.
#### Scenario: throws on failure
- **WHEN** `assertValidMedia(pngBytes, { allowedTypes: ["video"] })` is
invoked
- **THEN** a `MediaError` with code `MEDIA.VALIDATION_FAILED` MUST be
thrown.
**Verified by:** `src/validation/validation.test.ts::"returns metadata on success"` AND `src/validation/validation.test.ts::"throws VALIDATION_FAILED on failure"`
---
### Requirement: Observability bundle factory
The package SHALL expose `createMediaObservability(opts?)` returning a
`MediaObservability` bundle with `meter`, `tracer`, four counters
(`detectTotal`, `metadataTotal`, `validateTotal`, `errorTotal`), and two
histograms (`opLatencyMs`, `inputSizeBytes`). When `opts.observability` is
supplied the function MUST short-circuit and return the same instance.
#### Scenario: factory produces complete bundle
- **WHEN** `createMediaObservability()` is invoked with no options
- **THEN** the returned bundle MUST include `meter`, `tracer`, every
counter, and every histogram.
#### Scenario: pre-built bundle short-circuits
- **WHEN** `createMediaObservability({ observability: existing })` is
invoked
- **THEN** the returned bundle MUST be the same reference as `existing`.
#### Scenario: injected meter is preserved
- **WHEN** `createMediaObservability({ meter })` is invoked with a custom
meter
- **THEN** the returned bundle's `.meter` MUST be the injected instance.
**Verified by:** `src/observability/observability.test.ts::"returns a fully-populated bundle with global providers by default"` AND `src/observability/observability.test.ts::"short-circuits when a pre-built observability bundle is given"` AND `src/observability/observability.test.ts::"uses an injected meter when supplied"`

View File

@@ -0,0 +1,28 @@
# Tasks: enterprise-media
- [x] Read upstream package + enterprise audit.
- [x] Add `media` to `data` plugin in `scripts/folder-reorg/assignment.yml`.
- [x] Scaffold `packages/foundation/data/media/` with `package.json`,
`tsconfig.lib.json`, `vite.config.ts`, `vitest.config.ts`, README.
- [x] Author types module (`types/media.types.ts` + Zod schemas + `.md`).
- [x] Author errors module (`MEDIA_CODES`, `MEDIA_ERROR_METADATA`,
`MediaError`, `asMediaError` + tests + `.md`).
- [x] Author signatures module (`BUILTIN_SIGNATURES`,
`SignatureRegistry`, `defaultSignatureRegistry` + tests + `.md`).
- [x] Author observability module (`createMediaObservability` + tests +
`.md`).
- [x] Author detection module (`detectMediaType`, `detectSignature`,
`detectMediaTypeFromName`, `inferMimeFromSignature`,
`defaultMimeForType` + tests + `.md`).
- [x] Author metadata module (`getMetadata`, `getMetadataAsync` + tests
+ `.md`).
- [x] Author validation module (`validateMedia`, `validateMediaAsync`,
`assertValidMedia` + tests + `.md`).
- [x] Author root barrel + barrel test.
- [x] Run `bunx turbo lint typecheck test build --filter=@suaveplan/media`.
- [x] Run `bunx turbo test:coverage --filter=@suaveplan/media`.
- [x] Run `bun scripts/folder-reorg/generate-manifest.ts`.
- [x] Fold spec delta into `openspec/specs/media/spec.md`.
- [x] Archive change to `openspec/archive/2026-05-25-enterprise-media/`.
- [x] Flip `@suaveplan/media` row in `STATUS.md` to `✅`.
- [x] Commit on `feat/migrate-media` branch.