Move docs/ package mirror into document-navigator plugin
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>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# Detection
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Byte-level and filename-level media type detection. The module pairs the
|
||||
pluggable `SignatureRegistry` from `signatures/` with the MIME database
|
||||
exposed by `@suaveplan/mime` so consumers can identify image, video, and
|
||||
audio artefacts whether they have the bytes, the filename, or both.
|
||||
|
||||
## Features
|
||||
|
||||
- `detectMediaType(input, opts?)` — magic-byte detection via the registry.
|
||||
- `detectSignature(input, opts?)` — return the matched `MediaSignature`
|
||||
record, not just its `type`.
|
||||
- `detectMediaTypeFromName(filename, opts?)` — MIME-database lookup.
|
||||
- `inferMimeFromSignature(sig)` — canonical MIME for a matched signature
|
||||
with a sane fallback when no signature matched.
|
||||
- `defaultMimeForType(type)` — coarse fallback when only the
|
||||
category is known.
|
||||
- Counters and latency histograms emitted on every invocation.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { detectMediaType } from "@suaveplan/media";
|
||||
|
||||
const png = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d]);
|
||||
detectMediaType(png); // "image"
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
detectSignature,
|
||||
inferMimeFromSignature,
|
||||
SignatureRegistry,
|
||||
} from "@suaveplan/media";
|
||||
|
||||
const reg = new SignatureRegistry();
|
||||
reg.register({
|
||||
type: "image",
|
||||
label: "AVIF",
|
||||
bytes: [0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66],
|
||||
offset: 4,
|
||||
});
|
||||
const sig = detectSignature(myBytes, { registry: reg });
|
||||
const mime = inferMimeFromSignature(sig); // canonical MIME
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `DetectOptions` — `{ registry?, observability? }`.
|
||||
- `detectMediaType(input, opts?)` — `MediaType`.
|
||||
- `detectSignature(input, opts?)` — `MediaSignature | null`.
|
||||
- `detectMediaTypeFromName(filename, opts?)` — `MediaType`.
|
||||
- `inferMimeFromSignature(sig)` — canonical MIME string.
|
||||
- `defaultMimeForType(type)` — coarse fallback MIME.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`detectMediaType` and `detectMediaTypeFromName` both record an
|
||||
`op_latency_ms` histogram entry in a `finally` block so the cost of a
|
||||
detection call is always measured, even when the registry throws. The
|
||||
filename pathway uses `@suaveplan/mime`'s `getMimeType` so the database
|
||||
behind detection stays in lock-step with the rest of the project.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Errors
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the stable error-code registry, per-code metadata table, and the
|
||||
`MediaError` class that every public entrypoint throws or wraps. Every
|
||||
failure path in `@suaveplan/media` surfaces one of eight `MEDIA.*` codes
|
||||
so consumers (loggers, retry policies, telemetry pipelines, UI surfaces)
|
||||
can classify failures programmatically without parsing message strings.
|
||||
|
||||
## Features
|
||||
|
||||
- Frozen `MEDIA_CODES` registry created via `defineCodes("MEDIA", […])`.
|
||||
- Per-code `MediaCodeMetadata` record (`httpStatus`, `retryable`,
|
||||
`severity`, `description`) frozen at module load.
|
||||
- `MediaError` extending `SuaveplanError<MediaErrorCode>` — cause chain,
|
||||
redaction, OTel span-event adapter inherited.
|
||||
- `asMediaError(code, cause, fallback)` lift helper for `catch` sites.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { MediaError, MEDIA_CODES } from "@suaveplan/media";
|
||||
|
||||
throw new MediaError(MEDIA_CODES.EMPTY_INPUT, "input is empty");
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { asMediaError, MEDIA_CODES, MEDIA_ERROR_METADATA } from "@suaveplan/media";
|
||||
|
||||
try {
|
||||
/* boundary work */
|
||||
} catch (cause) {
|
||||
const err = asMediaError(
|
||||
MEDIA_CODES.PREDICATE_FAILED,
|
||||
cause,
|
||||
"predicate threw"
|
||||
);
|
||||
const meta = MEDIA_ERROR_METADATA[err.code];
|
||||
if (meta.retryable) {
|
||||
// schedule retry
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `MEDIA_CODES` — frozen code registry with eight namespaced keys.
|
||||
- `MediaErrorCode` — union of registry values.
|
||||
- `MEDIA_ERROR_METADATA` — frozen record keyed by code.
|
||||
- `MediaCodeMetadata` — per-code metadata shape.
|
||||
- `MediaError` — concrete `SuaveplanError` subclass with `.metadata` getter.
|
||||
- `asMediaError(code, cause, fallback)` — lift helper.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`defineCodes` produces namespaced keys (`MEDIA.EMPTY_INPUT`, …). The
|
||||
metadata table is `Object.freeze`'d at module top level so consumers
|
||||
cannot tamper at runtime. `asMediaError` preserves the original error as
|
||||
`.cause` when it's an `Error` instance, otherwise it wraps the stringified
|
||||
value so the cause chain is always populated.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Metadata
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Builds a `MediaMetadata` bundle (type, MIME, size, matched signature
|
||||
label) from raw bytes. The sync helper produces the base bundle in a
|
||||
single pass; the async helper layers a user-supplied
|
||||
`MediaMetadataExtractor` over the base so callers can fill in
|
||||
format-specific fields (width, height, duration) without forking the
|
||||
package.
|
||||
|
||||
## Features
|
||||
|
||||
- `getMetadata(input, opts?)` — synchronous, no extractor.
|
||||
- `getMetadataAsync(input, opts?)` — awaits the optional extractor and
|
||||
merges its return into the base bundle.
|
||||
- MIME resolution prefers the explicit `filename` field; otherwise it
|
||||
falls back to `inferMimeFromSignature`.
|
||||
- Signature label exposed via `metadata.signatureLabel` for downstream
|
||||
diagnostics.
|
||||
- Extractor errors are wrapped in `MediaError(MEDIA.METADATA_EXTRACTOR_FAILED)`
|
||||
with the original error chained as `.cause`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { getMetadata } from "@suaveplan/media";
|
||||
|
||||
const meta = getMetadata(new Uint8Array([0x89, 0x50, 0x4e, 0x47]), {
|
||||
filename: "logo.png",
|
||||
});
|
||||
console.log(meta.type, meta.mimeType, meta.size, meta.signatureLabel);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { getMetadataAsync } from "@suaveplan/media";
|
||||
|
||||
const meta = await getMetadataAsync(buf, {
|
||||
filename: "clip.mp4",
|
||||
extractor: async (_bytes, base) => {
|
||||
const { width, height, duration } = await probe(buf);
|
||||
return { ...base, width, height, duration };
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `MetadataOptions` — `{ filename?, registry?, observability?, extractor? }`.
|
||||
- `getMetadata(input, opts?)` — synchronous `MediaMetadata`.
|
||||
- `getMetadataAsync(input, opts?)` — `Promise<MediaMetadata>`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The base bundle is built inside a private helper so both entrypoints
|
||||
share signature detection + MIME resolution. The async variant only
|
||||
forks off the base when an extractor is supplied, so unused await paths
|
||||
incur near-zero overhead. Latency histograms are recorded in a
|
||||
`finally` block so failed extractor calls still produce telemetry.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Observability
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Constructs the OpenTelemetry instrument bundle threaded through every
|
||||
public entrypoint in `@suaveplan/media`. Each detection, metadata, and
|
||||
validation call increments a counter, records a latency histogram, and
|
||||
optionally emits a span. Consumers can inject their own meter / tracer
|
||||
to wire instruments into a shared telemetry pipeline.
|
||||
|
||||
## Features
|
||||
|
||||
- Four counters: `media_detect_total`, `media_metadata_total`,
|
||||
`media_validate_total`, `media_error_total`.
|
||||
- Two histograms: `media_op_latency_ms`, `media_input_size_bytes`.
|
||||
- Injectable meter / tracer or a pre-built `MediaObservability`.
|
||||
- Falls back to the global no-op providers when nothing is supplied,
|
||||
keeping the bundle safe to construct from library code.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createMediaObservability } from "@suaveplan/media";
|
||||
|
||||
const obs = createMediaObservability();
|
||||
obs.counters.detectTotal.add(1, { kind: "magic-bytes" });
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
import { createMediaObservability } from "@suaveplan/media";
|
||||
|
||||
const meter = metrics.getMeter("my-app");
|
||||
const obs = createMediaObservability({ meter });
|
||||
obs.histograms.opLatencyMs.record(12.4, { op: "validateMedia" });
|
||||
obs.counters.errorTotal.add(1, { code: "MEDIA.VALIDATION_FAILED" });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `MediaCounters` — counter set.
|
||||
- `MediaHistograms` — histogram set.
|
||||
- `MediaObservability` — bundle.
|
||||
- `MediaObservabilityOptions` — `{ meter?, tracer?, observability? }`.
|
||||
- `createMediaObservability(opts?)` — bundle factory.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
When `opts.observability` is supplied, it short-circuits before any
|
||||
instrument creation so injected bundles round-trip without mutation.
|
||||
Otherwise the function resolves a meter and tracer (defaulting to the
|
||||
global providers) and creates instruments via the helpers in
|
||||
`@suaveplan/opentelemetry` so naming + unit conventions stay consistent
|
||||
across the project.
|
||||
@@ -0,0 +1,71 @@
|
||||
# Signatures
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the magic-byte signature registry that powers byte-level detection.
|
||||
The module ships a frozen `BUILTIN_SIGNATURES` list covering common image
|
||||
(PNG, JPEG, GIF, BMP, WEBP, RIFF), video (MP4/MOV, WebM/MKV), and audio
|
||||
(MP3, FLAC, OGG) formats, plus a mutable `SignatureRegistry` class that
|
||||
lets downstream consumers add or remove entries without forking the
|
||||
package.
|
||||
|
||||
## Features
|
||||
|
||||
- Frozen built-in registry covering twelve canonical formats.
|
||||
- `SignatureRegistry` class with `register`, `unregister`, `list`,
|
||||
`match`, and `detect` methods.
|
||||
- Per-entry `offset` so ftyp-style signatures (MP4) and RIFF chunk markers
|
||||
(WebP) can match at non-zero positions.
|
||||
- Duplicate-label detection: `register` throws
|
||||
`MEDIA.DUPLICATE_SIGNATURE` if a second entry uses the same label.
|
||||
- Byte validation: registration rejects empty byte arrays and non-byte
|
||||
numbers with `MEDIA.INVALID_SIGNATURE`.
|
||||
- Process-wide `defaultSignatureRegistry` seeded with the built-ins.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { defaultSignatureRegistry } from "@suaveplan/media";
|
||||
|
||||
const png = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a]);
|
||||
const sig = defaultSignatureRegistry.match(png);
|
||||
console.log(sig?.label); // "PNG"
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { SignatureRegistry } from "@suaveplan/media";
|
||||
|
||||
const reg = new SignatureRegistry();
|
||||
reg.register({
|
||||
type: "image",
|
||||
label: "AVIF",
|
||||
bytes: [0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66],
|
||||
offset: 4,
|
||||
});
|
||||
const type = reg.detect(myBytes);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `BUILTIN_SIGNATURES` — readonly array of twelve canonical signatures.
|
||||
- `SignatureRegistry` — mutable registry class.
|
||||
- `register(sig)` — add entry; throws on duplicate label / invalid bytes.
|
||||
- `unregister(label)` — remove by label; returns whether removed.
|
||||
- `list()` — frozen snapshot.
|
||||
- `match(input)` — first matching `MediaSignature` or `null`.
|
||||
- `detect(input)` — `MediaType`, defaulting to `"unknown"`.
|
||||
- `defaultSignatureRegistry` — process-wide default.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`match` honours each signature's `offset` so non-zero-anchored formats
|
||||
work correctly. The built-in list orders longer / more-specific
|
||||
signatures before shorter ones (RIFF is listed after WEBP because the
|
||||
WEBP marker lives inside a RIFF container at offset 8). The registry's
|
||||
internal array is private so external mutation cannot break ordering.
|
||||
@@ -0,0 +1,69 @@
|
||||
# Media Types
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines every public type and Zod schema exported by `@suaveplan/media`.
|
||||
These contracts pin the package's surface so downstream consumers can write
|
||||
runtime-validated boundaries and compile against stable shapes. Types
|
||||
covered include `MediaType`, `MediaSignature`, `MediaMetadata`,
|
||||
`MediaConstraints`, `MediaResult`, the constraint predicate, and the async
|
||||
metadata-extractor hook.
|
||||
|
||||
## Features
|
||||
|
||||
- `MediaType` discriminated union (`image | video | audio | unknown`).
|
||||
- `MediaTypeSchema` and `MediaConstraintsSchema` Zod parsers for boundary
|
||||
validation.
|
||||
- `MediaSignature` model for magic-byte registry entries with optional
|
||||
non-zero offset.
|
||||
- Extended `MediaConstraints` (size floor + ceiling, MIME allowlist,
|
||||
duration ceiling, custom predicate).
|
||||
- `MediaMetadataExtractor` hook used by the metadata pipeline.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { MediaTypeSchema, type MediaMetadata } from "@suaveplan/media";
|
||||
|
||||
const parsed = MediaTypeSchema.parse("image");
|
||||
const meta: MediaMetadata = {
|
||||
type: parsed,
|
||||
mimeType: "image/png",
|
||||
size: 1024,
|
||||
};
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
MediaConstraintsSchema,
|
||||
type MediaConstraints,
|
||||
} from "@suaveplan/media";
|
||||
|
||||
const constraints: MediaConstraints = MediaConstraintsSchema.parse({
|
||||
maxSize: 2_000_000,
|
||||
allowedTypes: ["image"],
|
||||
allowedMimeTypes: ["image/png", "image/jpeg"],
|
||||
predicate: (m) => (m.size > 0 ? null : "empty"),
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `MediaType` — recognised media categories.
|
||||
- `MediaTypeSchema` — Zod enum for `MediaType`.
|
||||
- `MediaSignature` — magic-byte registry entry.
|
||||
- `MediaMetadata` — extracted metadata bundle.
|
||||
- `MediaConstraints` / `MediaConstraintsSchema` — validation rule set.
|
||||
- `MediaResult` — validation result with errors array.
|
||||
- `MediaConstraintPredicate` — custom validation function.
|
||||
- `MediaMetadataExtractor` — async metadata extension hook.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All schemas use `z` default-imported per Bun-safety. The predicate field
|
||||
in `MediaConstraintsSchema` uses `z.custom` because Zod cannot statically
|
||||
describe arbitrary function shapes. Arrays surface as `readonly` arrays in
|
||||
TypeScript so consumers cannot mutate constraint collections after
|
||||
construction.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Validation
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Validates media bytes against a `MediaConstraints` rule set covering
|
||||
size floors and ceilings, type allowlists, MIME allowlists, width /
|
||||
height / duration limits, and an optional custom predicate. The module
|
||||
exposes a synchronous helper for cheap byte-level checks and an async
|
||||
helper that also honours the constraint predicate plus the metadata
|
||||
extractor hook.
|
||||
|
||||
## Features
|
||||
|
||||
- `validateMedia(input, constraints, opts?)` — sync validation.
|
||||
- `validateMediaAsync(input, constraints, opts?)` — async validation
|
||||
that runs the predicate hook.
|
||||
- `assertValidMedia(...)` — throwing variant that yields
|
||||
`MediaError(MEDIA.VALIDATION_FAILED)` on failure.
|
||||
- Zod-validated constraints — malformed input throws
|
||||
`MediaError(MEDIA.INVALID_CONSTRAINTS)`; use `skipConstraintValidation`
|
||||
to opt out on hot paths.
|
||||
- Predicate failure wrapping — caller exceptions surface as
|
||||
`MediaError(MEDIA.PREDICATE_FAILED)` with the original error chained.
|
||||
- OTel `media_validate_total` counter + `media_op_latency_ms` histogram
|
||||
emitted on every invocation.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { validateMedia } from "@suaveplan/media";
|
||||
|
||||
const result = validateMedia(myBytes, {
|
||||
maxSize: 1_000_000,
|
||||
allowedTypes: ["image"],
|
||||
});
|
||||
if (!result.valid) {
|
||||
console.warn(result.errors);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { validateMediaAsync } from "@suaveplan/media";
|
||||
|
||||
const result = await validateMediaAsync(myBytes, {
|
||||
maxSize: 5_000_000,
|
||||
allowedTypes: ["image", "video"],
|
||||
allowedMimeTypes: ["image/png", "video/mp4"],
|
||||
maxWidth: 4096,
|
||||
maxHeight: 4096,
|
||||
maxDuration: 60,
|
||||
predicate: async (meta) =>
|
||||
meta.size === 0 ? "empty payload" : null,
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `ValidateOptions` — extends `MetadataOptions` with
|
||||
`skipConstraintValidation`.
|
||||
- `validateMedia(input, constraints, opts?)` — sync `MediaResult`.
|
||||
- `validateMediaAsync(input, constraints, opts?)` —
|
||||
`Promise<MediaResult>`.
|
||||
- `assertValidMedia(input, constraints, opts?)` — `MediaMetadata`,
|
||||
throws on validation failure.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`checkConstraints` is shared between the sync and async paths so the
|
||||
rule semantics are identical. Empty input is rejected up-front with
|
||||
`MEDIA.EMPTY_INPUT` before any metadata work happens. The predicate
|
||||
runs after every other check so callers can rely on the base errors
|
||||
being populated first.
|
||||
Reference in New Issue
Block a user