import { defineCodes, SuaveplanError } from "@suaveplan/error"; /** * Stable error codes for the `@suaveplan/streams-metadata` package. Every * code is reachable from a real call site in `src/`. */ export const STREAMS_METADATA_CODES = defineCodes("STREAMS_METADATA", [ "MIME_FAILED", "EXIF_FAILED", "INVALID_PAYLOAD", "ABORTED", ] as const); export type StreamsMetadataErrorCode = (typeof STREAMS_METADATA_CODES)[keyof typeof STREAMS_METADATA_CODES]; interface ErrorOpts { cause?: unknown; message?: string; } function asErrorCause(c: unknown): Error | undefined { return c instanceof Error ? c : undefined; } /** Base error class for every `@suaveplan/streams-metadata` failure. */ export class StreamsMetadataError extends SuaveplanError {} /** * Thrown by `MimeTransform` when MIME detection encounters an internal * exception. The documented `application/octet-stream` fallback does NOT * raise this — it is reserved for engine-level failures. */ export class MimeDetectionFailedError extends StreamsMetadataError { constructor(opts: ErrorOpts = {}) { super( STREAMS_METADATA_CODES.MIME_FAILED, opts.message ?? "MIME detection failed", { cause: asErrorCause(opts.cause) } ); } } /** * Thrown by `ExifTransform` when `@suaveplan/exif::readMetadata` raises. * Preserves the underlying `ExifError` on `cause`. */ export class ExifFailedError extends StreamsMetadataError { constructor(opts: ErrorOpts = {}) { super( STREAMS_METADATA_CODES.EXIF_FAILED, opts.message ?? "EXIF extraction failed", { cause: asErrorCause(opts.cause) } ); } } /** * Thrown when a transform receives a payload missing the mandatory `bytes` * field. */ export class InvalidPayloadError extends StreamsMetadataError { constructor(opts: ErrorOpts = {}) { super( STREAMS_METADATA_CODES.INVALID_PAYLOAD, opts.message ?? "Streams-metadata payload is missing required `bytes` Uint8Array" ); } } /** * Thrown when a transform is invoked with an already-aborted `AbortSignal` * by callers that want every error in the streams-metadata namespace. * Delegated to from `BaseTransform.assertNotAborted` indirectly when callers * opt in to the typed wrapping. */ export class MetadataAbortedError extends StreamsMetadataError { constructor(opts: ErrorOpts = {}) { super( STREAMS_METADATA_CODES.ABORTED, opts.message ?? "Streams-metadata operation aborted", { cause: asErrorCause(opts.cause) } ); } }