@dudousxd/nestjs-media
Version:
Filesystem + media-library for NestJS — one package
227 lines (219 loc) • 11.1 kB
TypeScript
import * as _dudousxd_nestjs_media_core from '@dudousxd/nestjs-media-core';
import { StorageManagerOptions, MediaStore, MediaCollectionConfig, ImageProcessor, UploadSessionStore, StorageManager, MediaLibrary, ResumableUploadManager, AttachmentManager, DirectUploadManager, StorageDriver, TusUploadHandler, MultipartPart } from '@dudousxd/nestjs-media-core';
export { AttachInput, ConversionNotDefinedError, CreateUploadInput, DriverCapabilities, FileNotFoundError, ImageProcessorMissingError, InvalidPartNumberError, ListEntry, ListOptions, ListResult, MediaCollectionConfig, MediaDiagnosticEvent, MediaLibrary, MediaNotFoundError, MediaRecord, MediaStore, MimeNotAllowedError, MultipartPart, PutOptions, ResumableUploadManager, StatResult, StorageDriver, StorageManager, TemporaryUrlOptions, UnknownDiskError, UnsupportedOperationError, UploadOffsetConflictError, UploadSession, UploadSessionListFilter, UploadSessionNotFoundError, UploadSessionStore, Visibility, mediaDiagnosticKey, publishMedia } from '@dudousxd/nestjs-media-core';
import { Type, CanActivate, DynamicModule } from '@nestjs/common';
interface MediaTusOptions {
disk: string;
basePath?: string;
maxSize?: number;
keyFor?: (filename: string, token: string, metadata: Record<string, string>) => string;
}
interface MediaDirectOptions {
disk: string;
basePath?: string;
partSize?: number;
}
interface MediaModuleOptions extends StorageManagerOptions {
/** Enable the media-library layer (layer 2) by providing a persistence store. */
store?: MediaStore;
collections?: MediaCollectionConfig[];
imageProcessor?: ImageProcessor;
/** Enable resumable (proxy) uploads by providing a session store. */
uploadSessions?: UploadSessionStore;
uploadTmpPrefix?: string;
/** Mount the tus HTTP controller (requires uploadSessions). */
tus?: MediaTusOptions;
/** Mount the direct (S3 multipart presign) upload controller. */
direct?: MediaDirectOptions;
/**
* Guard(s) for the upload controllers. A plain array gates ALL THREE (tus,
* multipart, direct) uniformly; the per-surface object form gates each
* controller with its own list (upload surfaces often carry different
* sensitivity — e.g. session creation admin-only, part PUTs any authenticated
* user). Third-party controller classes can't be annotated with `@UseGuards`
* by consumers, so without this option the upload surface is mounted with NO
* auth: anyone who can reach the app can upload. **Uploads are
* unauthenticated by default — set `guards` (or otherwise gate these routes,
* e.g. with a global guard) before exposing this module.**
*
* Guard classes are added to this module's `providers` so Nest can DI-instantiate
* them; if a guard has its own dependencies, pass the modules that provide them
* via `imports`.
*/
guards?: Type<CanActivate>[] | MediaUploadGuards;
/**
* Modules providing dependencies for `guards` (or anything else you inject into
* them). `forRoot` doesn't otherwise import anything, so this exists purely as
* an `imports` passthrough for guard wiring.
*/
imports?: DynamicModule['imports'];
}
interface MediaModuleAsyncOptions {
imports?: any[];
inject?: any[];
useFactory: (...args: any[]) => MediaModuleOptions | Promise<MediaModuleOptions>;
/**
* Guard(s) for the upload controllers — plain array gates all three
* uniformly, the per-surface object form gates each controller with its own
* list (see `MediaModuleOptions.guards`). This is a STATIC field on
* the async config object itself — NOT part of the options resolved by
* `useFactory` — because controllers (and the enhancers bound to them) are
* wired at module build time, before any async factory has run. If you need
* the guard to read async-resolved config (e.g. a secret from a ConfigService),
* have the guard itself inject that service via DI (see `imports`/`inject`
* above) rather than trying to pass it through `useFactory`.
*
* Same default-open caveat as `MediaModuleOptions.guards`: **omitting this
* leaves the upload surface unauthenticated.**
*/
guards?: Type<CanActivate>[] | MediaUploadGuards;
/**
* Static, build-time control over which upload controllers get mounted at
* all. Unlike `guards`, this can't be deferred to the async factory either —
* Nest registers controllers when the module is built, before `useFactory`
* runs — so `forRootAsync` mounts all three by default (each 501s when its
* underlying feature is left unconfigured by the factory). Set the ones you
* never configure to `false` so they don't exist as dead surface at all, e.g.
* `mount: { direct: false }` when you don't configure `direct` uploads.
*/
mount?: {
tus?: boolean;
multipart?: boolean;
direct?: boolean;
};
}
/**
* Per-surface guard lists. Each key gates one upload controller; an omitted key
* leaves that controller UNGUARDED (equivalent to `[]`), it does not fall back
* to some other surface's guards. Use the plain-array form of `guards` to gate
* all three uniformly.
*/
interface MediaUploadGuards {
/** Guards for `MediaUploadController` (tus session create/HEAD/PATCH). */
tus?: Type<CanActivate>[];
/** Guards for `MediaMultipartUploadController` (part PUTs + /complete). */
multipart?: Type<CanActivate>[];
/** Guards for `MediaDirectUploadController` (S3 presign endpoints). */
direct?: Type<CanActivate>[];
}
declare class MediaModule {
static forRoot(options: MediaModuleOptions): DynamicModule;
static forRootAsync(options: MediaModuleAsyncOptions): DynamicModule;
}
declare class MediaService {
private readonly manager;
private readonly mediaLibrary;
private readonly uploadManager;
private readonly attachmentManager;
private readonly directManager;
constructor(manager: StorageManager, mediaLibrary: MediaLibrary | null, uploadManager: ResumableUploadManager | null, attachmentManager: AttachmentManager, directManager: DirectUploadManager | null);
/** Attachment-as-column API (adonis-attachment style): `media.attachments.createFromFile(...)`. */
get attachments(): AttachmentManager;
/** Storage layer (layer 1): `media.disk('s3').put(...)`. */
disk(name?: string): StorageDriver;
/** Names of the configured disks (delegates to the storage manager). */
diskNames(): string[];
/** Media-library layer (layer 2). Throws if no store was configured. */
get library(): MediaLibrary;
/** Resumable (proxy) uploads. Throws if no upload session store was configured. */
get uploads(): ResumableUploadManager;
/** Direct (S3 multipart presign) uploads. Throws if not configured. */
get directUploads(): DirectUploadManager;
}
/** Minimal Express-like response surface this controller writes to. */
interface ResLike {
status(code: number): ResLike;
setHeader(name: string, value: string): void;
send(body?: string): void;
end(): void;
}
interface ReqLike$1 {
body?: Buffer;
}
/**
* tus endpoints. The app must register a raw-body parser for
* `application/offset+octet-stream` (e.g. `express.raw({ type: 'application/offset+octet-stream' })`)
* so PATCH bodies arrive as Buffers.
*/
declare class MediaUploadController {
private readonly handler;
constructor(handler: TusUploadHandler | null);
options(res: ResLike, headers: Record<string, string>): Promise<void>;
create(res: ResLike, headers: Record<string, string>): Promise<void>;
head(id: string, res: ResLike, headers: Record<string, string>): Promise<void>;
patch(id: string, req: ReqLike$1, res: ResLike, headers: Record<string, string>): Promise<void>;
remove(id: string, res: ResLike, headers: Record<string, string>): Promise<void>;
private run;
}
/** Express-like request exposing the raw body Buffer (host must mount a raw parser on the parts path). */
interface ReqLike {
body?: Buffer;
}
/**
* Proxy-parallel multipart routes. Bytes flow through the backend: the client
* PUTs each part (by explicit number) and the backend forwards it to a native
* S3 multipart part, then a single complete call assembles them. The key/disk
* are resolved from the session id — never from the client — so this is
* GameWarden-safe and cannot be pointed at another object.
*
* The app MUST mount a raw-body parser with a per-part size cap on
* `…/media/uploads/:id/parts/:n` so the PUT body arrives as a Buffer.
*/
declare class MediaMultipartUploadController {
private readonly manager;
constructor(manager: ResumableUploadManager | null);
private requireManager;
uploadPart(id: string, partNumber: string, req: ReqLike): Promise<_dudousxd_nestjs_media_core.MultipartPart>;
complete(id: string): Promise<{
key: string;
disk: string;
size: number;
}>;
listParts(id: string): Promise<{
parts: number[];
}>;
}
interface InitiateBody {
key: string;
contentType?: string;
size?: number;
partSize?: number;
disk?: string;
}
interface CompleteBody {
key: string;
parts: MultipartPart[];
disk?: string;
}
declare class MediaDirectUploadController {
private readonly manager;
constructor(manager: DirectUploadManager | null);
initiate(body: InitiateBody): Promise<_dudousxd_nestjs_media_core.DirectUploadCreated>;
presignPart(uploadId: string, partNumber: string, keyQuery: string | undefined, diskQuery: string | undefined, body: {
key?: string;
disk?: string;
}): Promise<{
url: string;
}>;
complete(uploadId: string, body: CompleteBody): Promise<{
key: string;
disk: string;
}>;
abort(uploadId: string, keyQuery: string | undefined, diskQuery: string | undefined, body: {
key?: string;
disk?: string;
}): Promise<void>;
}
declare const MEDIA_STORAGE: unique symbol;
declare const MEDIA_LIBRARY: unique symbol;
declare const MEDIA_UPLOADS: unique symbol;
declare const MEDIA_TUS: unique symbol;
declare const MEDIA_ATTACHMENTS: unique symbol;
declare const MEDIA_DIRECT: unique symbol;
/** The configured `MediaStore` (or `null`). Consumed by the media telescope dashboard. */
declare const MEDIA_STORE: unique symbol;
/** The configured `UploadSessionStore` (or `null`). Consumed by the media telescope dashboard. */
declare const MEDIA_UPLOAD_SESSIONS: unique symbol;
/** Alias for {@link MEDIA_STORAGE} (the `StorageManager`). Consumed by the media telescope dashboard. */
declare const MEDIA_STORAGE_SHARED: unique symbol;
export { MEDIA_ATTACHMENTS, MEDIA_DIRECT, MEDIA_LIBRARY, MEDIA_STORAGE, MEDIA_STORAGE_SHARED, MEDIA_STORE, MEDIA_TUS, MEDIA_UPLOADS, MEDIA_UPLOAD_SESSIONS, type MediaDirectOptions, MediaDirectUploadController, MediaModule, type MediaModuleAsyncOptions, type MediaModuleOptions, MediaMultipartUploadController, MediaService, type MediaTusOptions, MediaUploadController, type MediaUploadGuards };