@nestjs/platform-fastify 12.0.4 → 12.1.0

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 (57) hide show
  1. package/adapters/fastify-adapter.d.ts +48 -5
  2. package/adapters/fastify-adapter.js +137 -9
  3. package/index.d.ts +1 -0
  4. package/index.js +1 -0
  5. package/interfaces/external/fastify-multipart-options.interface.d.ts +53 -0
  6. package/interfaces/external/fastify-multipart-options.interface.js +1 -0
  7. package/interfaces/external/index.d.ts +1 -0
  8. package/interfaces/external/index.js +1 -0
  9. package/multipart/files.constants.d.ts +1 -0
  10. package/multipart/files.constants.js +1 -0
  11. package/multipart/index.d.ts +4 -0
  12. package/multipart/index.js +4 -0
  13. package/multipart/interceptors/any-files.interceptor.d.ts +12 -0
  14. package/multipart/interceptors/any-files.interceptor.js +13 -0
  15. package/multipart/interceptors/file-fields.interceptor.d.ts +13 -0
  16. package/multipart/interceptors/file-fields.interceptor.js +14 -0
  17. package/multipart/interceptors/file-stream.interceptor.d.ts +31 -0
  18. package/multipart/interceptors/file-stream.interceptor.js +32 -0
  19. package/multipart/interceptors/file.interceptor.d.ts +17 -0
  20. package/multipart/interceptors/file.interceptor.js +18 -0
  21. package/multipart/interceptors/files.interceptor.d.ts +14 -0
  22. package/multipart/interceptors/files.interceptor.js +15 -0
  23. package/multipart/interceptors/index.d.ts +6 -0
  24. package/multipart/interceptors/index.js +6 -0
  25. package/multipart/interceptors/no-files.interceptor.d.ts +12 -0
  26. package/multipart/interceptors/no-files.interceptor.js +13 -0
  27. package/multipart/interfaces/files-upload-module.interface.d.ts +18 -0
  28. package/multipart/interfaces/files-upload-module.interface.js +1 -0
  29. package/multipart/interfaces/index.d.ts +3 -0
  30. package/multipart/interfaces/index.js +3 -0
  31. package/multipart/interfaces/multipart-file.interface.d.ts +70 -0
  32. package/multipart/interfaces/multipart-file.interface.js +1 -0
  33. package/multipart/interfaces/multipart-options.interface.d.ts +77 -0
  34. package/multipart/interfaces/multipart-options.interface.js +1 -0
  35. package/multipart/multipart/append-field.util.d.ts +6 -0
  36. package/multipart/multipart/append-field.util.js +112 -0
  37. package/multipart/multipart/multipart-interceptor.factory.d.ts +13 -0
  38. package/multipart/multipart/multipart-interceptor.factory.js +130 -0
  39. package/multipart/multipart/multipart.constants.d.ts +55 -0
  40. package/multipart/multipart/multipart.constants.js +74 -0
  41. package/multipart/multipart/multipart.error.d.ts +10 -0
  42. package/multipart/multipart/multipart.error.js +15 -0
  43. package/multipart/multipart/multipart.parser.d.ts +39 -0
  44. package/multipart/multipart/multipart.parser.js +369 -0
  45. package/multipart/multipart/multipart.utils.d.ts +28 -0
  46. package/multipart/multipart/multipart.utils.js +54 -0
  47. package/multipart/multipart.constants.d.ts +1 -0
  48. package/multipart/multipart.constants.js +1 -0
  49. package/multipart/multipart.module.d.ts +18 -0
  50. package/multipart/multipart.module.js +75 -0
  51. package/multipart/storage/disk.storage.d.ts +24 -0
  52. package/multipart/storage/disk.storage.js +58 -0
  53. package/multipart/storage/index.d.ts +2 -0
  54. package/multipart/storage/index.js +2 -0
  55. package/multipart/storage/memory.storage.d.ts +8 -0
  56. package/multipart/storage/memory.storage.js +23 -0
  57. package/package.json +7 -2
@@ -1,16 +1,29 @@
1
1
  import { FastifyCorsOptions } from '@fastify/cors';
2
- import { Logger, type RequestMethod, type VersioningOptions } from '@nestjs/common';
2
+ import { Logger, type NestApplicationOptions, type RequestMethod, type VersioningOptions } from '@nestjs/common';
3
3
  import { FastifyBaseLogger, FastifyBodyParser, FastifyInstance, FastifyPluginAsync, FastifyPluginCallback, FastifyRegister, FastifyReply, FastifyRequest, FastifyServerOptions, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestGenericInterface, RouteGenericInterface } from 'fastify';
4
4
  import * as http from 'http';
5
5
  import * as http2 from 'http2';
6
6
  import * as https from 'https';
7
7
  import { InjectOptions, Chain as LightMyRequestChain, Response as LightMyRequestResponse } from 'light-my-request';
8
- import { type VersionValue } from '@nestjs/common/internal';
8
+ import { type SecurityRequestHook, type VersionValue } from '@nestjs/common/internal';
9
9
  import { AbstractHttpAdapter } from '@nestjs/core';
10
- import { FastifyStaticOptions, FastifyViewOptions } from '../interfaces/external/index.js';
10
+ import { FastifyMultipartOptions, FastifyStaticOptions, FastifyViewOptions } from '../interfaces/external/index.js';
11
11
  import { NestFastifyBodyParserOptions } from '../interfaces/index.js';
12
12
  type FastifyAdapterBaseOptions<Server extends RawServerBase = RawServerDefault, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyServerOptions<Server, Logger> & {
13
13
  skipMiddie?: boolean;
14
+ /**
15
+ * Controls the "@fastify/multipart" plugin (an optional peer dependency),
16
+ * which the upload interceptors from "@nestjs/platform-fastify/multipart"
17
+ * require.
18
+ *
19
+ * - unset (default): the adapter registers the plugin when an upload
20
+ * interceptor is used, unless it is already registered.
21
+ * - an object: plugin options (e.g. `limits`); the plugin is registered
22
+ * when the application initializes.
23
+ * - `true`: the same, with the plugin defaults.
24
+ * - `false`: the adapter never registers the plugin.
25
+ */
26
+ multipart?: boolean | FastifyMultipartOptions;
14
27
  };
15
28
  type FastifyHttp2SecureOptions<Server extends http2.Http2SecureServer, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyAdapterBaseOptions<Server, Logger> & {
16
29
  http2: true;
@@ -46,10 +59,15 @@ export declare class FastifyAdapter<TServer extends RawServerBase = RawServerDef
46
59
  protected readonly logger: Logger;
47
60
  protected readonly instance: TInstance;
48
61
  protected _pathPrefix?: string;
62
+ private readonly openConnections;
63
+ private isClosing;
49
64
  private _isParserRegistered;
50
65
  private onRequestHook?;
51
66
  private onResponseHook?;
52
67
  private isMiddieRegistered;
68
+ private multipartMode;
69
+ private multipartOptions;
70
+ private isMultipartRequested;
53
71
  private pendingMiddlewares;
54
72
  private versioningOptions?;
55
73
  private readonly versionConstraint;
@@ -89,10 +107,21 @@ export declare class FastifyAdapter<TServer extends RawServerBase = RawServerDef
89
107
  getHttpServer<T = TServer>(): T;
90
108
  getInstance<T = TInstance>(): T;
91
109
  register<TRegister extends Parameters<FastifyRegister<FastifyInstance<TServer, TRawRequest, TRawResponse>>>>(plugin: TRegister['0'], opts?: TRegister['1']): any;
110
+ /**
111
+ * Registers the "@fastify/multipart" plugin, unless the adapter's
112
+ * `multipart` option is `false`, or the plugin has been registered
113
+ * already by the time it loads. Idempotent. Called by the upload
114
+ * interceptors from "@nestjs/platform-fastify/multipart".
115
+ *
116
+ * The plugin is loaded lazily, and a missing package fails the
117
+ * application's startup (`ready()`) with an error naming the package,
118
+ * rather than exiting the process.
119
+ */
120
+ useMultipart(): void;
92
121
  inject(): LightMyRequestChain;
93
122
  inject(opts: InjectOptions | string): Promise<LightMyRequestResponse>;
94
- close(): Promise<undefined>;
95
- initHttpServer(): void;
123
+ close(): Promise<void>;
124
+ initHttpServer(options?: NestApplicationOptions): void;
96
125
  useStaticAssets(options: FastifyStaticOptions): Promise<any>;
97
126
  setViewEngine(options: FastifyViewOptions | string): Promise<any>;
98
127
  isHeadersSent(response: TReply): boolean;
@@ -104,6 +133,18 @@ export declare class FastifyAdapter<TServer extends RawServerBase = RawServerDef
104
133
  getRequestUrl(request: TRequest): string;
105
134
  getRequestUrl(request: TRawRequest): string;
106
135
  enableCors(options?: FastifyCorsOptions): void;
136
+ /**
137
+ * Runs the request hook of the built-in HTTP security features in an
138
+ * `onRequest` hook: before middie (Nest middleware), content-type parsing,
139
+ * guards and handlers, and also for unmatched routes. Headers set by the
140
+ * hook go to the Node.js response (`reply.raw`): Fastify merges them into
141
+ * every response it sends, errors and `404`s included, while
142
+ * `reply.header()` / `@Header()` values take precedence, and responses
143
+ * written to `reply.raw` directly (e.g. `@Sse()`) carry them too. A
144
+ * rejection goes to `done(error)`, i.e. to the Nest exception layer
145
+ * installed with `setErrorHandler()`.
146
+ */
147
+ registerSecurityHook(hook: SecurityRequestHook<TRequest>): void;
107
148
  registerParserMiddleware(prefix?: string, rawBody?: boolean): void;
108
149
  useBodyParser(type: string | string[] | RegExp, rawBody: boolean, options?: NestFastifyBodyParserOptions, parser?: FastifyBodyParser<Buffer, TServer>): void;
109
150
  createMiddlewareFactory(requestMethod: RequestMethod): Promise<(path: string, callback: Function) => any>;
@@ -144,5 +185,7 @@ export declare class FastifyAdapter<TServer extends RawServerBase = RawServerDef
144
185
  * and leaves any other request target untouched.
145
186
  */
146
187
  private getPathFromRequestTarget;
188
+ private trackOpenConnections;
189
+ private closeOpenConnections;
147
190
  }
148
191
  export {};
@@ -2,9 +2,10 @@ import { HttpException, HttpStatus, Logger, StreamableFile, VERSION_NEUTRAL, Ver
2
2
  import { fastify, } from 'fastify';
3
3
  import Reply from 'fastify/lib/reply.js';
4
4
  import fastifySymbols from 'fastify/lib/symbols.js';
5
+ import * as net from 'net';
5
6
  import { pathToRegexp } from 'path-to-regexp';
6
7
  import middie from '@fastify/middie';
7
- import { loadPackage, isNil, isString, isUndefined, } from '@nestjs/common/internal';
8
+ import { loadPackage, tryLoadPackage, isNil, isString, isUndefined, } from '@nestjs/common/internal';
8
9
  import { AbstractHttpAdapter } from '@nestjs/core';
9
10
  import { LegacyRouteConverter } from '@nestjs/core/internal';
10
11
  const { kRouteContext } = fastifySymbols;
@@ -13,16 +14,29 @@ import { parse as querystringParse } from 'fast-querystring';
13
14
  import urlSanitizer from 'find-my-way/lib/url-sanitizer.js';
14
15
  import { FASTIFY_ROUTE_CONFIG_METADATA, FASTIFY_ROUTE_CONSTRAINTS_METADATA, FASTIFY_ROUTE_SCHEMA_METADATA, } from '../constants.js';
15
16
  const { safeDecodeURI } = urlSanitizer;
17
+ const MISSING_MULTIPART_PACKAGE_MESSAGE = 'The "@fastify/multipart" package is missing. Please, make sure to install it (npm i @fastify/multipart) ' +
18
+ 'to use the file upload interceptors from "@nestjs/platform-fastify/multipart".';
19
+ function isFastifyMultipartPlugin(plugin) {
20
+ const fn = plugin?.default ?? plugin;
21
+ return (typeof fn === 'function' &&
22
+ (fn[Symbol.for('plugin-meta')]?.name === '@fastify/multipart' ||
23
+ fn.name === 'fastifyMultipart'));
24
+ }
16
25
  /**
17
26
  * @publicApi
18
27
  */
19
28
  export class FastifyAdapter extends AbstractHttpAdapter {
20
29
  logger = new Logger(FastifyAdapter.name);
21
30
  _pathPrefix;
31
+ openConnections = new Set();
32
+ isClosing = false;
22
33
  _isParserRegistered;
23
34
  onRequestHook;
24
35
  onResponseHook;
25
36
  isMiddieRegistered;
37
+ multipartMode = 'auto';
38
+ multipartOptions = {};
39
+ isMultipartRequested = false;
26
40
  pendingMiddlewares = [];
27
41
  versioningOptions;
28
42
  versionConstraint = {
@@ -110,6 +124,15 @@ export class FastifyAdapter extends AbstractHttpAdapter {
110
124
  if (instanceOrOptions?.skipMiddie) {
111
125
  this.isMiddieRegistered = true;
112
126
  }
127
+ const multipart = instanceOrOptions
128
+ ?.multipart;
129
+ if (multipart === false) {
130
+ this.multipartMode = 'off';
131
+ }
132
+ else if (multipart) {
133
+ this.multipartMode = 'eager';
134
+ this.multipartOptions = multipart === true ? {} : { ...multipart };
135
+ }
113
136
  this.instance.addHook('onRequest', (request, reply, done) => {
114
137
  if (this.onRequestHook) {
115
138
  this.onRequestHook(request, reply, done);
@@ -134,6 +157,9 @@ export class FastifyAdapter extends AbstractHttpAdapter {
134
157
  this.onResponseHook = hook;
135
158
  }
136
159
  async init() {
160
+ if (this.multipartMode === 'eager') {
161
+ this.useMultipart();
162
+ }
137
163
  if (this.isMiddieRegistered) {
138
164
  return;
139
165
  }
@@ -292,25 +318,79 @@ export class FastifyAdapter extends AbstractHttpAdapter {
292
318
  return this.instance;
293
319
  }
294
320
  register(plugin, opts) {
321
+ if (this.multipartMode !== 'off' &&
322
+ isFastifyMultipartPlugin(plugin) &&
323
+ !this.instance.hasRequestDecorator('isMultipart')) {
324
+ // The adapter owns the "@fastify/multipart" registration, so that the
325
+ // plugin is registered once whether or not the user registers it too.
326
+ // The user's options apply over the adapter's.
327
+ this.multipartOptions = { ...this.multipartOptions, ...opts };
328
+ this.useMultipart();
329
+ return this.instance;
330
+ }
295
331
  return this.instance.register(plugin, opts);
296
332
  }
333
+ /**
334
+ * Registers the "@fastify/multipart" plugin, unless the adapter's
335
+ * `multipart` option is `false`, or the plugin has been registered
336
+ * already by the time it loads. Idempotent. Called by the upload
337
+ * interceptors from "@nestjs/platform-fastify/multipart".
338
+ *
339
+ * The plugin is loaded lazily, and a missing package fails the
340
+ * application's startup (`ready()`) with an error naming the package,
341
+ * rather than exiting the process.
342
+ */
343
+ useMultipart() {
344
+ if (this.multipartMode === 'off' || this.isMultipartRequested) {
345
+ return;
346
+ }
347
+ this.isMultipartRequested = true;
348
+ const registerMultipart = async (instance) => {
349
+ // Plugins load in registration order, so one the user registered
350
+ // before this point has loaded by now.
351
+ if (instance.hasRequestDecorator('isMultipart')) {
352
+ return;
353
+ }
354
+ const multipart = await tryLoadPackage('@fastify/multipart', () => import('@fastify/multipart'));
355
+ if (!multipart) {
356
+ throw new Error(MISSING_MULTIPART_PACKAGE_MESSAGE);
357
+ }
358
+ // Copied: the plugin writes its defaults into the options it receives.
359
+ const { limits, ...options } = this.multipartOptions;
360
+ await instance.register(multipart, {
361
+ ...options,
362
+ ...(limits && { limits: { ...limits } }),
363
+ });
364
+ };
365
+ // Like `fastify-plugin`: register on the root context, not a child one.
366
+ Object.assign(registerMultipart, {
367
+ [Symbol.for('skip-override')]: true,
368
+ [Symbol.for('fastify.display-name')]: 'nestjs-multipart',
369
+ });
370
+ this.instance.register(registerMultipart);
371
+ }
297
372
  inject(opts) {
298
373
  return this.instance.inject(opts);
299
374
  }
300
375
  async close() {
376
+ this.isClosing = true;
301
377
  try {
302
- return await this.instance.close();
378
+ this.closeOpenConnections();
303
379
  }
304
- catch (err) {
305
- // Check if server is still running
306
- if (err.code !== 'ERR_SERVER_NOT_RUNNING') {
307
- throw err;
308
- }
309
- return;
380
+ finally {
381
+ await this.instance.close().catch(err => {
382
+ // Check if server is still running
383
+ if (err.code !== 'ERR_SERVER_NOT_RUNNING') {
384
+ throw err;
385
+ }
386
+ });
310
387
  }
311
388
  }
312
- initHttpServer() {
389
+ initHttpServer(options = {}) {
313
390
  this.httpServer = this.instance.server;
391
+ if (options?.forceCloseConnections) {
392
+ this.trackOpenConnections();
393
+ }
314
394
  }
315
395
  async useStaticAssets(options) {
316
396
  return this.register(await loadPackage('@fastify/static', 'FastifyAdapter.useStaticAssets()', () => import('@fastify/static')), options);
@@ -356,6 +436,22 @@ export class FastifyAdapter extends AbstractHttpAdapter {
356
436
  enableCors(options) {
357
437
  this.register(import('@fastify/cors'), options);
358
438
  }
439
+ /**
440
+ * Runs the request hook of the built-in HTTP security features in an
441
+ * `onRequest` hook: before middie (Nest middleware), content-type parsing,
442
+ * guards and handlers, and also for unmatched routes. Headers set by the
443
+ * hook go to the Node.js response (`reply.raw`): Fastify merges them into
444
+ * every response it sends, errors and `404`s included, while
445
+ * `reply.header()` / `@Header()` values take precedence, and responses
446
+ * written to `reply.raw` directly (e.g. `@Sse()`) carry them too. A
447
+ * rejection goes to `done(error)`, i.e. to the Nest exception layer
448
+ * installed with `setErrorHandler()`.
449
+ */
450
+ registerSecurityHook(hook) {
451
+ this.instance.addHook('onRequest', (request, reply, done) => {
452
+ done(hook(request, reply.raw));
453
+ });
454
+ }
359
455
  registerParserMiddleware(prefix, rawBody) {
360
456
  if (this._isParserRegistered) {
361
457
  return;
@@ -626,4 +722,36 @@ export class FastifyAdapter extends AbstractHttpAdapter {
626
722
  }
627
723
  return pathStart === -1 ? '/' : url.slice(pathStart);
628
724
  }
725
+ trackOpenConnections() {
726
+ const track = (socket) => {
727
+ if (this.isClosing) {
728
+ // Fastify runs its `preClose` hooks before it stops accepting
729
+ // connections, so destroy anything that arrives in the meantime
730
+ socket.destroy();
731
+ return;
732
+ }
733
+ if (this.openConnections.has(socket)) {
734
+ return;
735
+ }
736
+ this.openConnections.add(socket);
737
+ socket.on('close', () => this.openConnections.delete(socket));
738
+ };
739
+ this.httpServer.on('connection', track);
740
+ // Sockets accepted by the secondary servers Fastify binds for every
741
+ // address `listen()` resolves to are only reachable through requests.
742
+ // `inject()` requests carry a mock socket, which must not be tracked.
743
+ this.instance.addHook('onRequest', (request, _reply, done) => {
744
+ const socket = request.raw.socket;
745
+ if (socket instanceof net.Socket) {
746
+ track(socket);
747
+ }
748
+ done();
749
+ });
750
+ }
751
+ closeOpenConnections() {
752
+ for (const socket of this.openConnections) {
753
+ socket.destroy();
754
+ this.openConnections.delete(socket);
755
+ }
756
+ }
629
757
  }
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './adapters/index.js';
2
2
  export * from './interfaces/index.js';
3
3
  export * from './decorators/index.js';
4
+ export * from './multipart/index.js';
package/index.js CHANGED
@@ -7,3 +7,4 @@
7
7
  export * from './adapters/index.js';
8
8
  export * from './interfaces/index.js';
9
9
  export * from './decorators/index.js';
10
+ export * from './multipart/index.js';
@@ -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
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './fastify-static-options.interface.js';
2
2
  export * from './fastify-view-options.interface.js';
3
+ export * from './fastify-multipart-options.interface.js';
@@ -1,2 +1,3 @@
1
1
  export * from './fastify-static-options.interface.js';
2
2
  export * from './fastify-view-options.interface.js';
3
+ export * from './fastify-multipart-options.interface.js';
@@ -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
+ }