@nestjs/platform-fastify 11.2.5 → 11.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/interfaces/external/fastify-multipart-options.interface.d.ts +53 -0
  2. package/interfaces/external/fastify-multipart-options.interface.js +1 -0
  3. package/multipart/files.constants.d.ts +1 -0
  4. package/multipart/files.constants.js +1 -0
  5. package/multipart/index.d.ts +4 -0
  6. package/multipart/index.js +4 -0
  7. package/multipart/interceptors/any-files.interceptor.d.ts +12 -0
  8. package/multipart/interceptors/any-files.interceptor.js +13 -0
  9. package/multipart/interceptors/file-fields.interceptor.d.ts +13 -0
  10. package/multipart/interceptors/file-fields.interceptor.js +14 -0
  11. package/multipart/interceptors/file-stream.interceptor.d.ts +31 -0
  12. package/multipart/interceptors/file-stream.interceptor.js +32 -0
  13. package/multipart/interceptors/file.interceptor.d.ts +17 -0
  14. package/multipart/interceptors/file.interceptor.js +18 -0
  15. package/multipart/interceptors/files.interceptor.d.ts +14 -0
  16. package/multipart/interceptors/files.interceptor.js +15 -0
  17. package/multipart/interceptors/index.d.ts +6 -0
  18. package/multipart/interceptors/index.js +6 -0
  19. package/multipart/interceptors/no-files.interceptor.d.ts +12 -0
  20. package/multipart/interceptors/no-files.interceptor.js +13 -0
  21. package/multipart/interfaces/files-upload-module.interface.d.ts +18 -0
  22. package/multipart/interfaces/files-upload-module.interface.js +1 -0
  23. package/multipart/interfaces/index.d.ts +3 -0
  24. package/multipart/interfaces/index.js +3 -0
  25. package/multipart/interfaces/multipart-file.interface.d.ts +70 -0
  26. package/multipart/interfaces/multipart-file.interface.js +1 -0
  27. package/multipart/interfaces/multipart-options.interface.d.ts +77 -0
  28. package/multipart/interfaces/multipart-options.interface.js +1 -0
  29. package/multipart/multipart/append-field.util.d.ts +6 -0
  30. package/multipart/multipart/append-field.util.js +112 -0
  31. package/multipart/multipart/multipart-interceptor.factory.d.ts +13 -0
  32. package/multipart/multipart/multipart-interceptor.factory.js +130 -0
  33. package/multipart/multipart/multipart.constants.d.ts +55 -0
  34. package/multipart/multipart/multipart.constants.js +74 -0
  35. package/multipart/multipart/multipart.error.d.ts +10 -0
  36. package/multipart/multipart/multipart.error.js +15 -0
  37. package/multipart/multipart/multipart.parser.d.ts +39 -0
  38. package/multipart/multipart/multipart.parser.js +369 -0
  39. package/multipart/multipart/multipart.utils.d.ts +28 -0
  40. package/multipart/multipart/multipart.utils.js +54 -0
  41. package/multipart/multipart.constants.d.ts +1 -0
  42. package/multipart/multipart.constants.js +1 -0
  43. package/multipart/multipart.module.d.ts +18 -0
  44. package/multipart/multipart.module.js +75 -0
  45. package/multipart/storage/disk.storage.d.ts +24 -0
  46. package/multipart/storage/disk.storage.js +58 -0
  47. package/multipart/storage/index.d.ts +2 -0
  48. package/multipart/storage/index.js +2 -0
  49. package/multipart/storage/memory.storage.d.ts +8 -0
  50. package/multipart/storage/memory.storage.js +23 -0
  51. package/package.json +2 -2
@@ -0,0 +1,53 @@
1
+ /**
2
+ * "@fastify/multipart" plugin options, as accepted by the FastifyAdapter's
3
+ * `multipart` option. Declared locally so the adapter's typings do not
4
+ * require the (optional) plugin to be installed.
5
+ *
6
+ * `attachFieldsToBody` is deliberately left out: it consumes the body before
7
+ * the upload interceptors from "@nestjs/platform-fastify/multipart" run.
8
+ *
9
+ * @see https://github.com/fastify/fastify-multipart/blob/main/types/index.d.ts
10
+ * @publicApi
11
+ */
12
+ export interface FastifyMultipartOptions {
13
+ /**
14
+ * Limits applied to every multipart request. The upload interceptors merge
15
+ * their own `limits` over these.
16
+ */
17
+ limits?: {
18
+ /**
19
+ * Max field name size in bytes. Not enforced by the plugin for multipart
20
+ * bodies; the upload interceptors enforce their own `limits.fieldNameSize`.
21
+ */
22
+ fieldNameSize?: number;
23
+ /** Max field value size in bytes (Default: 1 MiB) */
24
+ fieldSize?: number;
25
+ /** Max number of non-file fields (Default: Infinity) */
26
+ fields?: number;
27
+ /** Max file size in bytes (Default: the Fastify `bodyLimit`, 1 MiB) */
28
+ fileSize?: number;
29
+ /** Max number of file fields (Default: Infinity) */
30
+ files?: number;
31
+ /** Max number of header key => value pairs (Default: 2000) */
32
+ headerPairs?: number;
33
+ /** Max number of parts, fields and files together (Default: 1000) */
34
+ parts?: number;
35
+ };
36
+ /**
37
+ * Throw when a file exceeds `limits.fileSize` while it is read through
38
+ * `req.file()` / `req.files()`. The upload interceptors always reject such
39
+ * a file, whatever this is set to.
40
+ */
41
+ throwFileSizeLimit?: boolean;
42
+ /** Keep the full path of files instead of just the base name (Default: false) */
43
+ preservePath?: boolean;
44
+ /** Default character set for part header values (Default: 'latin1') */
45
+ defParamCharset?: string;
46
+ /** Default character set when one isn't defined (Default: 'utf8') */
47
+ defCharset?: string;
48
+ /**
49
+ * Detect if a part is a file. By default a part is a file if its content
50
+ * type is `application/octet-stream` or it has a file name.
51
+ */
52
+ isPartAFile?: (fieldName: string | undefined, contentType: string | undefined, fileName: string | undefined) => boolean;
53
+ }
@@ -0,0 +1 @@
1
+ export declare const MULTIPART_MODULE_OPTIONS = "MULTIPART_MODULE_OPTIONS";
@@ -0,0 +1 @@
1
+ export const MULTIPART_MODULE_OPTIONS = 'MULTIPART_MODULE_OPTIONS';
@@ -0,0 +1,4 @@
1
+ export * from './interceptors/index.js';
2
+ export * from './interfaces/index.js';
3
+ export * from './multipart.module.js';
4
+ export * from './storage/index.js';
@@ -0,0 +1,4 @@
1
+ export * from './interceptors/index.js';
2
+ export * from './interfaces/index.js';
3
+ export * from './multipart.module.js';
4
+ export * from './storage/index.js';
@@ -0,0 +1,12 @@
1
+ import type { NestInterceptor, Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from '../interfaces/index.js';
3
+ /**
4
+ * Accepts every file, in any field, and exposes them as an array in
5
+ * `req.files` (`@UploadedFiles()`). The Fastify counterpart of
6
+ * platform-express's `AnyFilesInterceptor`.
7
+ *
8
+ * @param localOptions options merged over the `MultipartModule` defaults
9
+ *
10
+ * @publicApi
11
+ */
12
+ export declare function AnyFilesInterceptor(localOptions?: MultipartOptions): Type<NestInterceptor>;
@@ -0,0 +1,13 @@
1
+ import { createMultipartInterceptor } from '../multipart/multipart-interceptor.factory.js';
2
+ /**
3
+ * Accepts every file, in any field, and exposes them as an array in
4
+ * `req.files` (`@UploadedFiles()`). The Fastify counterpart of
5
+ * platform-express's `AnyFilesInterceptor`.
6
+ *
7
+ * @param localOptions options merged over the `MultipartModule` defaults
8
+ *
9
+ * @publicApi
10
+ */
11
+ export function AnyFilesInterceptor(localOptions) {
12
+ return createMultipartInterceptor({ fields: 'ANY', strategy: 'ARRAY' }, localOptions);
13
+ }
@@ -0,0 +1,13 @@
1
+ import type { NestInterceptor, Type } from '@nestjs/common';
2
+ import type { MultipartField, MultipartOptions } from '../interfaces/index.js';
3
+ /**
4
+ * Accepts files in each of `uploadFields` and exposes them grouped by field
5
+ * name in `req.files` (`@UploadedFiles()`). The Fastify counterpart of
6
+ * platform-express's `FileFieldsInterceptor`.
7
+ *
8
+ * @param uploadFields accepted fields, each with an optional `maxCount`
9
+ * @param localOptions options merged over the `MultipartModule` defaults
10
+ *
11
+ * @publicApi
12
+ */
13
+ export declare function FileFieldsInterceptor(uploadFields: MultipartField[], localOptions?: MultipartOptions): Type<NestInterceptor>;
@@ -0,0 +1,14 @@
1
+ import { createMultipartInterceptor } from '../multipart/multipart-interceptor.factory.js';
2
+ /**
3
+ * Accepts files in each of `uploadFields` and exposes them grouped by field
4
+ * name in `req.files` (`@UploadedFiles()`). The Fastify counterpart of
5
+ * platform-express's `FileFieldsInterceptor`.
6
+ *
7
+ * @param uploadFields accepted fields, each with an optional `maxCount`
8
+ * @param localOptions options merged over the `MultipartModule` defaults
9
+ *
10
+ * @publicApi
11
+ */
12
+ export function FileFieldsInterceptor(uploadFields, localOptions) {
13
+ return createMultipartInterceptor({ fields: uploadFields, strategy: 'OBJECT' }, localOptions);
14
+ }
@@ -0,0 +1,31 @@
1
+ import type { NestInterceptor, Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from '../interfaces/index.js';
3
+ /**
4
+ * Hands the route handler a single file in `fieldName` as a stream
5
+ * (`req.file.stream`, see `MultipartFileStream`), without buffering it or
6
+ * writing it to disk. Fastify only; there is no platform-express
7
+ * counterpart.
8
+ *
9
+ * - Text fields must precede the file in the form: parts that follow it are
10
+ * not parsed.
11
+ * - Whatever the handler leaves unread is discarded before the response is
12
+ * sent, so that the client can finish uploading. When the handler returns
13
+ * a `StreamableFile` (which may be the upload itself), it is discarded
14
+ * once the response has been sent instead. So a handler that responds
15
+ * with a `StreamableFile` of something other than the upload should read
16
+ * the upload first: otherwise, when the connection is not kept alive
17
+ * (`Connection: close`), Node.js closes it right after the response, and
18
+ * a client still uploading fails with EPIPE / ECONNRESET.
19
+ * - A file in any other field fails the request with a 400.
20
+ * - The file size is unknown up front, so `MaxFileSizeValidator` does not
21
+ * apply, and neither does `FileTypeValidator`'s magic-number check.
22
+ * - Once `limits.fileSize` is exceeded, the stream errors with a
23
+ * `PayloadTooLargeException`.
24
+ *
25
+ * @param fieldName name of the form field that carries the file
26
+ * @param localOptions options merged over the `MultipartModule` defaults
27
+ * (`dest` and `storage` do not apply)
28
+ *
29
+ * @publicApi
30
+ */
31
+ export declare function FileStreamInterceptor(fieldName: string, localOptions?: Omit<MultipartOptions, 'dest' | 'storage'>): Type<NestInterceptor>;
@@ -0,0 +1,32 @@
1
+ import { createMultipartStreamInterceptor } from '../multipart/multipart-interceptor.factory.js';
2
+ /**
3
+ * Hands the route handler a single file in `fieldName` as a stream
4
+ * (`req.file.stream`, see `MultipartFileStream`), without buffering it or
5
+ * writing it to disk. Fastify only; there is no platform-express
6
+ * counterpart.
7
+ *
8
+ * - Text fields must precede the file in the form: parts that follow it are
9
+ * not parsed.
10
+ * - Whatever the handler leaves unread is discarded before the response is
11
+ * sent, so that the client can finish uploading. When the handler returns
12
+ * a `StreamableFile` (which may be the upload itself), it is discarded
13
+ * once the response has been sent instead. So a handler that responds
14
+ * with a `StreamableFile` of something other than the upload should read
15
+ * the upload first: otherwise, when the connection is not kept alive
16
+ * (`Connection: close`), Node.js closes it right after the response, and
17
+ * a client still uploading fails with EPIPE / ECONNRESET.
18
+ * - A file in any other field fails the request with a 400.
19
+ * - The file size is unknown up front, so `MaxFileSizeValidator` does not
20
+ * apply, and neither does `FileTypeValidator`'s magic-number check.
21
+ * - Once `limits.fileSize` is exceeded, the stream errors with a
22
+ * `PayloadTooLargeException`.
23
+ *
24
+ * @param fieldName name of the form field that carries the file
25
+ * @param localOptions options merged over the `MultipartModule` defaults
26
+ * (`dest` and `storage` do not apply)
27
+ *
28
+ * @publicApi
29
+ */
30
+ export function FileStreamInterceptor(fieldName, localOptions) {
31
+ return createMultipartStreamInterceptor(fieldName, localOptions);
32
+ }
@@ -0,0 +1,17 @@
1
+ import type { NestInterceptor, Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from '../interfaces/index.js';
3
+ /**
4
+ * Accepts a single file in `fieldName` and exposes it as `req.file`
5
+ * (`@UploadedFile()`), with the text fields in `req.body`. The Fastify
6
+ * counterpart of platform-express's `FileInterceptor`.
7
+ *
8
+ * Requires the `@fastify/multipart` package, which the FastifyAdapter
9
+ * registers as a plugin when an upload interceptor is used (see its
10
+ * `multipart` option).
11
+ *
12
+ * @param fieldName name of the form field that carries the file
13
+ * @param localOptions options merged over the `MultipartModule` defaults
14
+ *
15
+ * @publicApi
16
+ */
17
+ export declare function FileInterceptor(fieldName: string, localOptions?: MultipartOptions): Type<NestInterceptor>;
@@ -0,0 +1,18 @@
1
+ import { createMultipartInterceptor } from '../multipart/multipart-interceptor.factory.js';
2
+ /**
3
+ * Accepts a single file in `fieldName` and exposes it as `req.file`
4
+ * (`@UploadedFile()`), with the text fields in `req.body`. The Fastify
5
+ * counterpart of platform-express's `FileInterceptor`.
6
+ *
7
+ * Requires the `@fastify/multipart` package, which the FastifyAdapter
8
+ * registers as a plugin when an upload interceptor is used (see its
9
+ * `multipart` option).
10
+ *
11
+ * @param fieldName name of the form field that carries the file
12
+ * @param localOptions options merged over the `MultipartModule` defaults
13
+ *
14
+ * @publicApi
15
+ */
16
+ export function FileInterceptor(fieldName, localOptions) {
17
+ return createMultipartInterceptor({ fields: [{ name: fieldName, maxCount: 1 }], strategy: 'VALUE' }, localOptions);
18
+ }
@@ -0,0 +1,14 @@
1
+ import type { NestInterceptor, Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from '../interfaces/index.js';
3
+ /**
4
+ * Accepts up to `maxCount` files in `fieldName` and exposes them as an array
5
+ * in `req.files` (`@UploadedFiles()`). The Fastify counterpart of
6
+ * platform-express's `FilesInterceptor`.
7
+ *
8
+ * @param fieldName name of the form field that carries the files
9
+ * @param maxCount maximum number of files to accept
10
+ * @param localOptions options merged over the `MultipartModule` defaults
11
+ *
12
+ * @publicApi
13
+ */
14
+ export declare function FilesInterceptor(fieldName: string, maxCount?: number, localOptions?: MultipartOptions): Type<NestInterceptor>;
@@ -0,0 +1,15 @@
1
+ import { createMultipartInterceptor } from '../multipart/multipart-interceptor.factory.js';
2
+ /**
3
+ * Accepts up to `maxCount` files in `fieldName` and exposes them as an array
4
+ * in `req.files` (`@UploadedFiles()`). The Fastify counterpart of
5
+ * platform-express's `FilesInterceptor`.
6
+ *
7
+ * @param fieldName name of the form field that carries the files
8
+ * @param maxCount maximum number of files to accept
9
+ * @param localOptions options merged over the `MultipartModule` defaults
10
+ *
11
+ * @publicApi
12
+ */
13
+ export function FilesInterceptor(fieldName, maxCount, localOptions) {
14
+ return createMultipartInterceptor({ fields: [{ name: fieldName, maxCount }], strategy: 'ARRAY' }, localOptions);
15
+ }
@@ -0,0 +1,6 @@
1
+ export * from './any-files.interceptor.js';
2
+ export * from './file-fields.interceptor.js';
3
+ export * from './file-stream.interceptor.js';
4
+ export * from './file.interceptor.js';
5
+ export * from './files.interceptor.js';
6
+ export * from './no-files.interceptor.js';
@@ -0,0 +1,6 @@
1
+ export * from './any-files.interceptor.js';
2
+ export * from './file-fields.interceptor.js';
3
+ export * from './file-stream.interceptor.js';
4
+ export * from './file.interceptor.js';
5
+ export * from './files.interceptor.js';
6
+ export * from './no-files.interceptor.js';
@@ -0,0 +1,12 @@
1
+ import type { NestInterceptor, Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from '../interfaces/index.js';
3
+ /**
4
+ * Accepts text fields only (exposed in `req.body`); any file fails the
5
+ * request with a 400. The Fastify counterpart of platform-express's
6
+ * `NoFilesInterceptor`.
7
+ *
8
+ * @param localOptions options merged over the `MultipartModule` defaults
9
+ *
10
+ * @publicApi
11
+ */
12
+ export declare function NoFilesInterceptor(localOptions?: MultipartOptions): Type<NestInterceptor>;
@@ -0,0 +1,13 @@
1
+ import { createMultipartInterceptor } from '../multipart/multipart-interceptor.factory.js';
2
+ /**
3
+ * Accepts text fields only (exposed in `req.body`); any file fails the
4
+ * request with a 400. The Fastify counterpart of platform-express's
5
+ * `NoFilesInterceptor`.
6
+ *
7
+ * @param localOptions options merged over the `MultipartModule` defaults
8
+ *
9
+ * @publicApi
10
+ */
11
+ export function NoFilesInterceptor(localOptions) {
12
+ return createMultipartInterceptor({ fields: [], strategy: 'NONE' }, localOptions);
13
+ }
@@ -0,0 +1,18 @@
1
+ import type { InjectionToken, ModuleMetadata, OptionalFactoryDependency, Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from './multipart-options.interface.js';
3
+ export type MultipartModuleOptions = MultipartOptions;
4
+ /**
5
+ * @publicApi
6
+ */
7
+ export interface MultipartOptionsFactory {
8
+ createMultipartOptions(): Promise<MultipartModuleOptions> | MultipartModuleOptions;
9
+ }
10
+ /**
11
+ * @publicApi
12
+ */
13
+ export interface MultipartModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
14
+ useExisting?: Type<MultipartOptionsFactory>;
15
+ useClass?: Type<MultipartOptionsFactory>;
16
+ useFactory?: (...args: any[]) => Promise<MultipartModuleOptions> | MultipartModuleOptions;
17
+ inject?: Array<InjectionToken | OptionalFactoryDependency>;
18
+ }
@@ -0,0 +1,3 @@
1
+ export * from './files-upload-module.interface.js';
2
+ export * from './multipart-file.interface.js';
3
+ export * from './multipart-options.interface.js';
@@ -0,0 +1,3 @@
1
+ export * from './files-upload-module.interface.js';
2
+ export * from './multipart-file.interface.js';
3
+ export * from './multipart-options.interface.js';
@@ -0,0 +1,70 @@
1
+ import type { Readable } from 'stream';
2
+ /**
3
+ * A stored upload, in the shape multer produces (`Express.Multer.File`), so
4
+ * `@UploadedFile()`, `ParseFilePipe` and the built-in file validators work
5
+ * unchanged. Memory storage sets `buffer`; disk storage sets `destination`,
6
+ * `filename` and `path`.
7
+ *
8
+ * @publicApi
9
+ */
10
+ export interface UploadedMultipartFile {
11
+ /** Field name specified in the form */
12
+ fieldname: string;
13
+ /** Name of the file on the user's computer */
14
+ originalname: string;
15
+ /** Encoding type of the file */
16
+ encoding: string;
17
+ /** Mime type of the file */
18
+ mimetype: string;
19
+ /** Size of the file in bytes */
20
+ size: number;
21
+ /** A Buffer of the entire file (memory storage) */
22
+ buffer?: Buffer;
23
+ /** The folder to which the file has been saved (disk storage) */
24
+ destination?: string;
25
+ /** The name of the file within the destination (disk storage) */
26
+ filename?: string;
27
+ /** Location of the uploaded file (disk storage) */
28
+ path?: string;
29
+ }
30
+ /**
31
+ * What a storage engine and `fileFilter` see before the file is stored.
32
+ *
33
+ * @publicApi
34
+ */
35
+ export interface IncomingMultipartFile {
36
+ /** Field name specified in the form */
37
+ fieldname: string;
38
+ /** Name of the file on the user's computer */
39
+ originalname: string;
40
+ /** Encoding type of the file */
41
+ encoding: string;
42
+ /** Mime type of the file */
43
+ mimetype: string;
44
+ /**
45
+ * The file contents. Non-enumerable; meant to be consumed by
46
+ * `MultipartStorageEngine._handleFile` only.
47
+ */
48
+ readonly stream: Readable;
49
+ }
50
+ /**
51
+ * The file `FileStreamInterceptor` hands to the route handler. Its size is
52
+ * not known up front.
53
+ *
54
+ * @publicApi
55
+ */
56
+ export interface MultipartFileStream {
57
+ /** Field name specified in the form */
58
+ fieldname: string;
59
+ /** Name of the file on the user's computer */
60
+ originalname: string;
61
+ /** Encoding type of the file */
62
+ encoding: string;
63
+ /** Mime type of the file */
64
+ mimetype: string;
65
+ /**
66
+ * The file contents. Errors with a `PayloadTooLargeException` once
67
+ * `limits.fileSize` is exceeded.
68
+ */
69
+ stream: Readable;
70
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,77 @@
1
+ import type { IncomingMultipartFile, UploadedMultipartFile } from './multipart-file.interface.js';
2
+ /**
3
+ * multer's storage engine contract (`_handleFile` / `_removeFile`), kept
4
+ * as-is so existing multer storage engines can be passed as `storage`.
5
+ *
6
+ * @publicApi
7
+ */
8
+ export interface MultipartStorageEngine {
9
+ _handleFile(req: any, file: IncomingMultipartFile, callback: (error?: any, info?: Partial<UploadedMultipartFile>) => void): void;
10
+ _removeFile(req: any, file: UploadedMultipartFile, callback: (error: Error | null) => void): void;
11
+ }
12
+ /**
13
+ * Same keys as platform-express's `MulterLimits`.
14
+ *
15
+ * Limits that are not set fall back to the options `@fastify/multipart` was
16
+ * registered with, and then to its own defaults. Unlike multer (which
17
+ * defaults `fileSize` and `parts` to `Infinity`), `@fastify/multipart` caps
18
+ * `fileSize` at the Fastify instance's `bodyLimit` (1 MiB unless configured)
19
+ * and `parts` at 1000.
20
+ *
21
+ * @publicApi
22
+ */
23
+ export interface MultipartLimits {
24
+ /**
25
+ * Max field name size in bytes (Default: unlimited). Unlike the other
26
+ * limits, it does not fall back to the options `@fastify/multipart` was
27
+ * registered with.
28
+ */
29
+ fieldNameSize?: number;
30
+ /** Max field value size (Default: 1MB) */
31
+ fieldSize?: number;
32
+ /** Max number of non-file fields (Default: Infinity) */
33
+ fields?: number;
34
+ /** For multipart forms, the max file size in bytes (Default: the Fastify `bodyLimit`, 1 MiB) */
35
+ fileSize?: number;
36
+ /** For multipart forms, the max number of file fields (Default: Infinity) */
37
+ files?: number;
38
+ /** For multipart forms, the max number of parts (fields + files) (Default: 1000) */
39
+ parts?: number;
40
+ /** For multipart forms, the max number of header key => value pairs to parse (Default: 2000) */
41
+ headerPairs?: number;
42
+ }
43
+ /**
44
+ * Same keys and semantics as platform-express's `MulterOptions`, so option
45
+ * objects can be moved between adapters as-is.
46
+ *
47
+ * @publicApi
48
+ */
49
+ export interface MultipartOptions {
50
+ /** Where to store the files (disk storage). Ignored when `storage` is set. */
51
+ dest?: string;
52
+ /** The storage engine to use for uploaded files (Default: memory storage). */
53
+ storage?: MultipartStorageEngine;
54
+ /**
55
+ * An object specifying the size limits, or a function of the request that
56
+ * returns one. Merged over the limits `@fastify/multipart` was registered with.
57
+ */
58
+ limits?: MultipartLimits | ((req: any) => MultipartLimits);
59
+ /** Keep the full path of files instead of just the base name (Default: false) */
60
+ preservePath?: boolean;
61
+ /** Default character set for part header values (e.g. filename) (Default: 'latin1') */
62
+ defParamCharset?: string;
63
+ /**
64
+ * Decides which files are stored. Call `callback(null, false)` to skip a
65
+ * file, or `callback(error, false)` to fail the request with `error`.
66
+ */
67
+ fileFilter?(req: any, file: IncomingMultipartFile, callback: (error: Error | null, acceptFile: boolean) => void): void;
68
+ }
69
+ /**
70
+ * @publicApi
71
+ */
72
+ export interface MultipartField {
73
+ /** The field name. */
74
+ name: string;
75
+ /** Optional maximum number of files per field to accept. */
76
+ maxCount?: number;
77
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Appends a text field to `store` using multer's bracket notation.
3
+ * Returns `false` (leaving `store` untouched) for names that would pollute a
4
+ * prototype.
5
+ */
6
+ export declare function appendField(store: object, key: string, value: unknown): boolean;
@@ -0,0 +1,112 @@
1
+ const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
2
+ function parsePath(key) {
3
+ const failure = () => [{ type: 'object', key, last: true }];
4
+ const firstKey = /^[^[]*/.exec(key)[0];
5
+ if (!firstKey) {
6
+ return failure();
7
+ }
8
+ let pos = firstKey.length;
9
+ let tail = { type: 'object', key: firstKey };
10
+ const steps = [tail];
11
+ while (pos < key.length) {
12
+ if (key[pos] === '[' && key[pos + 1] === ']') {
13
+ pos += 2;
14
+ tail.append = true;
15
+ if (pos !== key.length) {
16
+ return failure();
17
+ }
18
+ continue;
19
+ }
20
+ const rest = key.substring(pos);
21
+ let match = /^\[(\d+)\]/.exec(rest);
22
+ if (match) {
23
+ pos += match[0].length;
24
+ tail.nextType = 'array';
25
+ tail = { type: 'array', key: parseInt(match[1], 10) };
26
+ steps.push(tail);
27
+ continue;
28
+ }
29
+ match = /^\[([^\]]+)\]/.exec(rest);
30
+ if (match) {
31
+ pos += match[0].length;
32
+ tail.nextType = 'object';
33
+ tail = { type: 'object', key: match[1] };
34
+ steps.push(tail);
35
+ continue;
36
+ }
37
+ return failure();
38
+ }
39
+ tail.last = true;
40
+ return steps;
41
+ }
42
+ function valueType(value) {
43
+ if (value === undefined) {
44
+ return 'undefined';
45
+ }
46
+ if (Array.isArray(value)) {
47
+ return 'array';
48
+ }
49
+ if (typeof value === 'object') {
50
+ return 'object';
51
+ }
52
+ return 'scalar';
53
+ }
54
+ function setLastValue(ctx, step, current, value) {
55
+ switch (valueType(current)) {
56
+ case 'undefined':
57
+ ctx[step.key] = step.append ? [value] : value;
58
+ break;
59
+ case 'array':
60
+ ctx[step.key].push(value);
61
+ break;
62
+ case 'object':
63
+ return setLastValue(current, { type: 'object', key: '', last: true }, current[''], value);
64
+ case 'scalar':
65
+ ctx[step.key] = [ctx[step.key], value];
66
+ break;
67
+ }
68
+ return ctx;
69
+ }
70
+ function setValue(ctx, step, current, value) {
71
+ if (step.last) {
72
+ return setLastValue(ctx, step, current, value);
73
+ }
74
+ let obj;
75
+ switch (valueType(current)) {
76
+ case 'undefined':
77
+ ctx[step.key] = step.nextType === 'array' ? [] : Object.create(null);
78
+ return ctx[step.key];
79
+ case 'object':
80
+ return current;
81
+ case 'array':
82
+ if (step.nextType === 'array') {
83
+ return current;
84
+ }
85
+ obj = Object.create(null);
86
+ ctx[step.key] = obj;
87
+ current.forEach((item, i) => {
88
+ if (item !== undefined) {
89
+ obj['' + i] = item;
90
+ }
91
+ });
92
+ return obj;
93
+ case 'scalar':
94
+ obj = Object.create(null);
95
+ obj[''] = current;
96
+ ctx[step.key] = obj;
97
+ return obj;
98
+ }
99
+ }
100
+ /**
101
+ * Appends a text field to `store` using multer's bracket notation.
102
+ * Returns `false` (leaving `store` untouched) for names that would pollute a
103
+ * prototype.
104
+ */
105
+ export function appendField(store, key, value) {
106
+ const steps = parsePath(key);
107
+ if (steps.some(step => FORBIDDEN_KEYS.has(String(step.key)))) {
108
+ return false;
109
+ }
110
+ steps.reduce((ctx, step) => setValue(ctx, step, ctx[step.key], value), store);
111
+ return true;
112
+ }
@@ -0,0 +1,13 @@
1
+ import { type NestInterceptor, type Type } from '@nestjs/common';
2
+ import type { MultipartOptions } from '../interfaces/index.js';
3
+ import { type UploadSpec } from './multipart.parser.js';
4
+ /**
5
+ * Creates an interceptor that parses the multipart body with multer's
6
+ * semantics, as described by `spec`.
7
+ */
8
+ export declare function createMultipartInterceptor(spec: UploadSpec, localOptions?: MultipartOptions): Type<NestInterceptor>;
9
+ /**
10
+ * Creates an interceptor that hands the route handler the stream of a single
11
+ * file in `fieldName`.
12
+ */
13
+ export declare function createMultipartStreamInterceptor(fieldName: string, localOptions?: MultipartOptions): Type<NestInterceptor>;