# Media API reference

> Current emitted signatures and options for @db3.ai/app/media.

- Package: `@db3.ai/app/media`
- Canonical page: [https://db3.ai/docs/media-api](https://db3.ai/docs/media-api)
- Markdown: [https://db3.ai/docs/media-api.md](https://db3.ai/docs/media-api.md)
- Framework source of truth: `packages/app/src/media/README.md`

<a id="start"></a>

## Imports and examples

Import supported APIs from `@db3.ai/app/media`. These signatures come from the staged package used by consumers. Relative filenames in declarations describe type dependencies; they are not extra supported deep imports.

Use the guide for setup, executable examples, failure handling and ownership. A signature is not proof that every deployment or provider has been exercised.

- [Guide, examples and testing](https://db3.ai/docs/media.md)

<a id="manager"></a>

## Managed file and library operations

### Managed file and library operations

```typescript
import type { Readable } from 'node:stream';
import type { Storage } from '../storage/index.js';
import type { MediaOptions } from './contracts/index.js';
import { type ImageProcessor, type ImageVariant, type ImageVariantOptions } from './image/index.js';
import { MediaFile } from './MediaFile.js';
import { MediaItem } from './MediaItem.js';
import { MediaLibrary } from './MediaLibrary.js';
import type { MediaAttachFileInput, MediaFolderInput, MediaLibraryInput, MediaLibraryScope, MediaStoreFileInput, MediaStoreFileStreamInput, MediaStoreReconstructedVisibleImageStreamInput, MediaStoredVisibleFile, MediaStoreVisibleFileInput, MediaStoreVisibleFileStreamInput } from './types.js';
/**
 * Framework service for managed media libraries, files, and browser items.
 *
 * Storage remains responsible for bytes. This manager records file metadata,
 * scopes files through media libraries, and creates optional folder-tree rows
 * for media browser UIs.
 */
export declare class MediaManager {
    #private;
    private readonly storage;
    /**
     * Creates a media manager backed by the application storage service.
     *
     * @param storage - Storage manager used to write and read file bytes.
     * @param options - Media rendering and derived-file cache configuration.
     * @param imageProcessor - Concrete image processing engine.
     */
    constructor(storage: Storage, options?: MediaOptions, imageProcessor?: ImageProcessor);
    /**
     * Finds or creates the media library for an application-owned scope.
     *
     * @param input - Scope identity and defaults for a new library.
     * @returns Existing or newly-created media library.
     *
     * @example
     * const library = await app.media.libraryFor({
     * 	scopeType: 'scout.website',
     * 	scopeId: website.id,
     * 	key: 'default',
     * 	name: 'Website media',
     * });
     */
    libraryFor(input: MediaLibraryScope): Promise<MediaLibrary>;
    /**
     * Loads one media library by id.
     *
     * @param id - Media library ULID.
     * @returns Media library row or null.
     */
    library(id: string): Promise<MediaLibrary | null>;
    /**
     * Loads one managed file by id.
     *
     * @param id - Managed file ULID.
     * @returns Managed file row or null.
     */
    file(id: string): Promise<MediaFile | null>;
    /**
     * Writes bytes to storage and records a managed file row.
     *
     * The file is not visible in the media browser until `attachFile()` creates a
     * `MediaItem` that points to it.
     *
     * @param input - File contents, library, storage options, and metadata.
     * @returns Managed file row.
     */
    storeFile(input: MediaStoreFileInput): Promise<MediaFile>;
    /**
     * Streams bytes to storage and records a managed file row.
     *
     * This is the preferred media finalization path for resumable uploads because
     * completed temporary files do not need to be buffered in application memory.
     *
     * @param input - File stream, library, storage options, and metadata.
     * @returns Managed file row.
     */
    storeFileStream(input: MediaStoreFileStreamInput): Promise<MediaFile>;
    /**
     * Reads managed file bytes from the storage disk recorded on the file row.
     *
     * @param fileOrId - Managed file row or id.
     * @returns Stored file bytes.
     */
    readFile(fileOrId: MediaFile | string): Promise<Buffer>;
    /**
     * Opens a managed file as a storage-backed readable stream.
     *
     * @param fileOrId - Managed file row or ULID.
     * @returns Stream containing the stored file bytes.
     */
    readFileStream(fileOrId: MediaFile | string): Promise<Readable>;
    /**
     * Renders a responsive managed image into the configured disposable cache.
     *
     * @param fileOrId - Managed image row or ULID.
     * @param options - Requested responsive image dimensions.
     * @returns Rendered image stream and cache metadata.
     *
     * @example
     * const image = await app.media.renderImage(imageId, {
     * 	width: 640,
     * });
     */
    renderImage(fileOrId: MediaFile | string, options: ImageVariantOptions): Promise<ImageVariant>;
    /**
     * Permanently deletes a managed file, its browser placements, and stored bytes.
     *
     * Browser item rows are removed through their database foreign key to the
     * managed file. Disposable responsive-image variants are cleared before the
     * durable source bytes and database record are removed.
     *
     * @param fileOrId - Managed file row or ULID to permanently delete.
     */
    deleteFile(fileOrId: MediaFile | string): Promise<void>;
    /**
     * Finds or creates the root browser item for a library.
     *
     * @param libraryOrId - Media library row or id.
     * @returns Root browser item for the library.
     */
    rootFor(libraryOrId: MediaLibraryInput): Promise<MediaItem>;
    /**
     * Finds or creates a slash-prefixed browser folder path.
     *
     * @param input - Library and folder path to ensure.
     * @returns Folder item for the requested path, or the root for `/`.
     */
    ensureFolder(input: MediaFolderInput): Promise<MediaItem>;
    /**
     * Places an existing managed file into the browser tree.
     *
     * @param input - File, target library, folder path, and optional item metadata.
     * @returns Browser item pointing at the managed file.
     */
    attachFile(input: MediaAttachFileInput): Promise<MediaItem>;
    /**
     * Writes bytes to storage and creates a browser item for the file.
     *
     * @param input - File storage input plus optional browser placement.
     * @returns Stored file and browser item rows.
     */
    storeVisibleFile(input: MediaStoreVisibleFileInput): Promise<MediaStoredVisibleFile>;
    /**
     * Streams bytes to storage and creates a browser item for the file.
     *
     * @param input - File stream and storage input plus optional browser placement.
     * @returns Stored file and browser item rows.
     */
    storeVisibleFileStream(input: MediaStoreVisibleFileStreamInput): Promise<MediaStoredVisibleFile>;
    /**
     * Fully decodes and reconstructs an untrusted image before durable storage.
     *
     * The processor emits new canonical bytes without source metadata or trailing
     * payloads. No media row becomes visible unless the complete processor stream
     * is successfully written.
     *
     * @param input - Untrusted image stream and browser placement metadata.
     * @returns Stored reconstructed file and browser item rows.
     */
    storeReconstructedVisibleImageStream(input: MediaStoreReconstructedVisibleImageStreamInput): Promise<MediaStoredVisibleFile>;
}
```

<a id="inputs"></a>

## Inputs and results

### Inputs and results

```typescript
import type { Readable } from 'node:stream';
import type { StorageContents } from '../storage/index.js';
import type { MediaFileVisibility } from './constants.js';
import type { MediaFile } from './MediaFile.js';
import type { MediaItem } from './MediaItem.js';
import type { MediaLibrary } from './MediaLibrary.js';
/**
 * App-owned scope used to find or create a media library.
 */
export interface MediaLibraryScope {
    /** Opaque scope type such as `scout.website` or `scout.organization`. */
    scopeType: string;
    /** Opaque app-owned scope id. */
    scopeId: string;
    /** Scope-local library key. Defaults to `default`. */
    key?: string;
    /** Human-readable library name used when a new library is created. */
    name?: string;
    /** Optional default storage disk for files written into this library. */
    defaultDisk?: string | null;
    /** Optional storage path prefix for files written into this library. */
    pathPrefix?: string | null;
    /** Optional app-owned library metadata. */
    meta?: Record<string, unknown> | null;
}
/**
 * Library input accepted by media manager methods.
 */
export type MediaLibraryInput = MediaLibrary | string;
/**
 * Input for writing a managed file without making it visible in the browser.
 */
export interface MediaStoreFileInput {
    /** Existing media library or library id that will own the file. */
    library: MediaLibraryInput;
    /** File bytes or text accepted by the storage layer. */
    contents: StorageContents;
    /** Optional display filename. Defaults to the file id plus MIME extension. */
    name?: string | null;
    /** MIME type recorded on the file and passed to storage writes. */
    mimeType?: string | null;
    /** Optional storage disk override. Defaults to the library disk or app default. */
    disk?: string | null;
    /** Optional storage path override. Defaults to a library-scoped generated path. */
    path?: string | null;
    /** Optional app-owned source label such as generated-image or upload. */
    source?: string | null;
    /** Storage visibility used for the write. Defaults to private. */
    visibility?: MediaFileVisibility | null;
    /** Optional known byte size. Defaults to the byte length of the supplied contents. */
    size?: number | null;
    /** Optional app-owned file metadata. */
    meta?: Record<string, unknown> | null;
}
/**
 * Input for streaming a managed file without buffering it in application memory.
 */
export interface MediaStoreFileStreamInput extends Omit<MediaStoreFileInput, 'contents'> {
    /** Readable stream containing the file bytes. */
    stream: Readable;
    /** Known byte size, or null when storage should measure the completed stream. */
    size?: number | null;
}
/**
 * Input for showing an existing managed file in the browser tree.
 */
export interface MediaAttachFileInput {
    /** Existing media library or library id that owns the browser tree. */
    library: MediaLibraryInput;
    /** Managed file or file id to place in the browser. */
    file: MediaFile | string;
    /** Slash-prefixed folder path. Defaults to the library root. */
    folderPath?: string | null;
    /** Optional browser row name. Defaults to the file name. */
    name?: string | null;
    /** Optional app-owned item metadata. */
    meta?: Record<string, unknown> | null;
}
/**
 * Input for writing a file and immediately placing it in the browser tree.
 */
export interface MediaStoreVisibleFileInput extends MediaStoreFileInput {
    /** Slash-prefixed folder path for the browser item. Defaults to the library root. */
    folderPath?: string | null;
    /** Optional browser row name. Defaults to the stored filename. */
    itemName?: string | null;
    /** Optional browser item metadata. */
    itemMeta?: Record<string, unknown> | null;
}
/**
 * Input for streaming a file and immediately placing it in the browser tree.
 */
export interface MediaStoreVisibleFileStreamInput extends MediaStoreFileStreamInput {
    /** Slash-prefixed folder path for the browser item. Defaults to the library root. */
    folderPath?: string | null;
    /** Optional browser row name. Defaults to the stored filename. */
    itemName?: string | null;
    /** Optional browser item metadata. */
    itemMeta?: Record<string, unknown> | null;
}
/**
 * Input for reconstructing an image stream before durable browser placement.
 */
export interface MediaStoreReconstructedVisibleImageStreamInput extends Omit<MediaStoreVisibleFileStreamInput, 'mimeType' | 'size'> {
    /** Allowlisted source MIME type used for decoding and canonical output. */
    mimeType: string;
}
/**
 * Result returned after a file is written and placed in the browser tree.
 */
export interface MediaStoredVisibleFile {
    /** Library that owns the file and item. */
    library: MediaLibrary;
    /** Managed file row for loading bytes by ULID. */
    file: MediaFile;
    /** Browser-visible item row that points at the managed file. */
    item: MediaItem;
}
/**
 * Input for creating or finding a browser folder.
 */
export interface MediaFolderInput {
    /** Existing media library or library id that owns the browser tree. */
    library: MediaLibraryInput;
    /** Slash-prefixed folder path to ensure. */
    path: string;
    /** Optional folder metadata applied only when a folder is created. */
    meta?: Record<string, unknown> | null;
}
```

<a id="options"></a>

## Service options

### Service options

```typescript
import type { ImageVariantCacheOptions } from '../image/contracts/index.js';
/**
 * Framework media-service configuration.
 */
export interface MediaOptions {
    /** Responsive-image rendering and disposable cache configuration. */
    images?: ImageVariantCacheOptions;
}
```

<a id="file"></a>

## File model

### File model

```typescript
import { ActiveRecord, type FieldBuilder } from '../db/index.js';
import type { EntityRef } from '../db/fields/LinkField.js';
import { MEDIA_FILE_VISIBILITY } from './constants.js';
import { MediaLibrary } from './MediaLibrary.js';
/**
 * Managed file record for bytes stored through the framework storage service.
 *
 * A file can be managed without appearing in a media browser. Browser placement
 * is represented separately by `MediaItem` rows that point to this file.
 */
export declare class MediaFile extends ActiveRecord {
    static table: string;
    static primaryKey: string;
    static labelFields: string[];
    static comment: string;
    /**
     * Defines managed file metadata and storage location fields.
     *
     * @param field - ActiveRecord field builder.
     * @returns Field definitions for schema generation and value conversion.
     */
    static fields(field: FieldBuilder): {
        id: import("../db/index.js").UlidField;
        library: import("../db/index.js").LinkField<MediaLibrary>;
        disk: import("../db/index.js").StringField;
        path: import("../db/index.js").StringField;
        name: import("../db/index.js").StringField;
        mimeType: import("../db/index.js").StringField;
        size: import("../db/index.js").IntegerField;
        visibility: import("../db/index.js").ChoiceStringField;
        source: import("../db/index.js").StringField;
        meta: import("../db/index.js").JsonField<Record<string, unknown> | null>;
        createdAt: import("../db/index.js").TimestampField;
        updatedAt: import("../db/index.js").TimestampField;
    };
    id: string | null;
    library: EntityRef<MediaLibrary>;
    disk: string | null;
    path: string | null;
    name: string | null;
    mimeType: string | null;
    size: number | null;
    visibility: typeof MEDIA_FILE_VISIBILITY[keyof typeof MEDIA_FILE_VISIBILITY] | null;
    source: string | null;
    meta: Record<string, unknown> | null;
    createdAt: Date | null;
    updatedAt: Date | null;
}
```

<a id="library"></a>

## Library model

### Library model

```typescript
import { ActiveRecord, type FieldBuilder } from '../db/index.js';
/**
 * Scoped namespace for managed files and browser-visible media items.
 *
 * Apps use `scopeType`, `scopeId`, and `key` to map their own ownership model
 * onto the framework media tables without adding app-specific columns such as
 * `website_id` or `organization_id`.
 */
export declare class MediaLibrary extends ActiveRecord {
    static table: string;
    static primaryKey: string;
    static labelFields: string[];
    static comment: string;
    /**
     * Defines the media library schema and scope identity indexes.
     *
     * @param field - ActiveRecord field builder.
     * @returns Field definitions for schema generation and value conversion.
     */
    static fields(field: FieldBuilder): {
        id: import("../db/index.js").UlidField;
        scopeType: import("../db/index.js").StringField;
        scopeId: import("../db/index.js").StringField;
        key: import("../db/index.js").StringField;
        name: import("../db/index.js").StringField;
        defaultDisk: import("../db/index.js").StringField;
        pathPrefix: import("../db/index.js").StringField;
        meta: import("../db/index.js").JsonField<Record<string, unknown> | null>;
        createdAt: import("../db/index.js").TimestampField;
        updatedAt: import("../db/index.js").TimestampField;
    };
    id: string | null;
    scopeType: string | null;
    scopeId: string | null;
    key: string | null;
    name: string | null;
    defaultDisk: string | null;
    pathPrefix: string | null;
    meta: Record<string, unknown> | null;
    createdAt: Date | null;
    updatedAt: Date | null;
}
```

<a id="item"></a>

## Browser item model

### Browser item model

```typescript
import { ActiveRecord, type FieldBuilder } from '../db/index.js';
import type { EntityRef } from '../db/fields/LinkField.js';
import { type MediaItemType } from './constants.js';
import { MediaFile } from './MediaFile.js';
import { MediaLibrary } from './MediaLibrary.js';
/**
 * Folder-tree row used by media browser surfaces.
 *
 * Files can exist without media items. A `file` media item is only created when
 * the managed file should be visible inside a library browser.
 */
export declare class MediaItem extends ActiveRecord {
    static table: string;
    static primaryKey: string;
    static labelFields: string[];
    static comment: string;
    /**
     * Defines media browser tree fields and library-scoped path indexes.
     *
     * @param field - ActiveRecord field builder.
     * @returns Field definitions for schema generation and value conversion.
     */
    static fields(field: FieldBuilder): {
        id: import("../db/index.js").UlidField;
        library: import("../db/index.js").LinkField<MediaLibrary>;
        type: import("../db/index.js").ChoiceStringField;
        root: import("../db/index.js").LinkField<MediaItem>;
        parent: import("../db/index.js").LinkField<MediaItem>;
        file: import("../db/index.js").LinkField<MediaFile>;
        name: import("../db/index.js").StringField;
        path: import("../db/index.js").StringField;
        meta: import("../db/index.js").JsonField<Record<string, unknown> | null>;
        createdAt: import("../db/index.js").TimestampField;
        updatedAt: import("../db/index.js").TimestampField;
    };
    id: string | null;
    library: EntityRef<MediaLibrary>;
    type: MediaItemType | null;
    root: EntityRef<MediaItem> | null;
    parent: EntityRef<MediaItem> | null;
    file: EntityRef<MediaFile> | null;
    name: string | null;
    path: string | null;
    meta: Record<string, unknown> | null;
    createdAt: Date | null;
    updatedAt: Date | null;
}
```

<a id="request"></a>

## Image request parsing

### Image request parsing

```typescript
import type { ImageVariantOptions } from './contracts/index.js';
/**
 * Error raised when an untrusted image variant request cannot be translated
 * into an allowlisted framework command.
 */
export declare class ImageVariantRequestError extends RangeError {
    readonly code: 'invalid_image_width';
    /**
     * Creates an invalid image request error.
     *
     * @param message - Safe explanation suitable for an HTTP error response.
     * @param code - Stable application error code for HTTP adapters.
     */
    constructor(message: string, code: 'invalid_image_width');
}
/**
 * Translates URL query parameters into a safe image variant command.
 *
 * Only documented parameters are interpreted. Unknown parameters are ignored
 * and no processor option is accepted directly from the request.
 *
 * @param searchParams - URL query parameters supplied by an HTTP adapter.
 * @returns Validated variant options, or null when the original is requested.
 *
 * @example
 * const options = imageVariantOptionsFromSearchParams(requestUrl.searchParams);
 */
export declare function imageVariantOptionsFromSearchParams(searchParams: URLSearchParams): ImageVariantOptions | null;
```

<a id="processor"></a>

## Image processing contract

### Image processing contract

```typescript
import type { Duplex } from 'node:stream';
/**
 * Allowlisted image transformation passed to a concrete processing engine.
 */
export interface ImageProcessorCommand {
    /** Normalized MIME type of the encoded source stream. */
    sourceMimeType: string;
    /** Normalized MIME type the processor must emit. */
    outputMimeType: string;
    /** Maximum output width in pixels, or null to preserve source dimensions. */
    width: number | null;
}
/**
 * Canonical image reconstruction passed to a concrete processing engine.
 *
 * Reconstruction decodes the complete untrusted input and emits a new image
 * without preserving source metadata or trailing source bytes.
 */
export interface ImageProcessorReconstructionCommand {
    /** Normalized MIME type already identified from the encoded source stream. */
    sourceMimeType: string;
    /** Normalized MIME type the processor must use for the reconstructed image. */
    outputMimeType: string;
}
/**
 * Adapter implemented by a concrete image processing engine.
 *
 * The framework owns request parsing, cache identity, storage, and concurrency.
 * Processors only translate a trusted command into a bounded transform stream.
 */
export interface ImageProcessor {
    /**
     * Creates a stream that transforms encoded source bytes into an image variant.
     *
     * @param command - Validated transformation command.
     * @returns Duplex stream that accepts source bytes and emits encoded output.
     */
    transform(command: ImageProcessorCommand): Duplex;
    /**
     * Creates a stream that fully decodes and reconstructs an untrusted image.
     *
     * @param command - Validated canonical reconstruction command.
     * @returns Duplex stream that accepts source bytes and emits reconstructed bytes.
     */
    reconstruct(command: ImageProcessorReconstructionCommand): Duplex;
}
```

<a id="variant"></a>

## Variant results

### Variant results

```typescript
import type { Readable } from 'node:stream';
/**
 * Maximum rendered image width accepted by the framework.
 *
 * Bounding width protects the application from accidental or malicious
 * requests that would create excessively large decoded images.
 */
export declare const MAX_IMAGE_VARIANT_WIDTH = 4096;
/**
 * Options that identify one cached responsive image variant.
 */
export interface ImageVariantOptions {
    /**
     * Requested pixel width. Aspect ratio is preserved and images are never
     * enlarged. Omit the width to compress the source at its original dimensions.
     */
    width?: number;
}
/**
 * Storage-backed responsive image returned by the media service.
 */
export interface ImageVariant {
    /** Rendered image stream loaded from durable storage. */
    stream: Readable;
    /** MIME type of the rendered bytes. */
    mimeType: string;
    /** Storage path used on the configured disposable cache disk, or null for passthrough images. */
    path: string | null;
    /** Whether the bytes were loaded from an existing generated variant. */
    cached: boolean;
}
```

<a id="cache"></a>

## Variant cache options

### Variant cache options

```typescript
/**
 * Storage configuration for disposable responsive-image variants.
 *
 * Generated variants are derived from durable managed files and may be removed
 * at any time. A missing variant is regenerated on the next image request.
 */
export interface ImageVariantCacheOptions {
    /**
     * Named storage disk used for generated variants.
     *
     * Omit this value to use the managed source file's disk.
     */
    cacheDisk?: string;
    /**
     * Relative directory containing generated variants on the cache disk.
     *
     * Defaults to `image-cache`.
     */
    cachePrefix?: string;
}
```

<a id="error"></a>

## Reconstruction failures

### Reconstruction failures

```typescript
/**
 * Indicates that untrusted source bytes could not be decoded and reconstructed.
 *
 * Storage and database failures remain their original error types so callers
 * can distinguish invalid image input from application infrastructure errors.
 */
export declare class ImageReconstructionError extends Error {
    /**
     * Creates an image reconstruction error with its processor failure attached.
     *
     * @param message - Stable application-facing failure summary.
     * @param options - Standard error options containing the processor cause.
     */
    constructor(message: string, options?: ErrorOptions);
}
```

## Related documentation
- [Media](https://db3.ai/docs/media.md): Give files durable IDs and project-scoped libraries. Keep storage paths, browser folders and permission checks separate.

## Guidance for AI tools
Use the documented public import `@db3.ai/app/media` and its exported types. Prefer the source-backed examples and behavioural outcomes above over invented APIs or source-relative internal imports.
