UNPKG

@dudousxd/nestjs-media

Version:

Filesystem + media-library for NestJS — one package

227 lines (219 loc) 11.1 kB
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 };