@eggjs/multipart 4.0.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.
- package/LICENSE +21 -0
- package/README.md +444 -0
- package/dist/commonjs/app/extend/context.d.ts +110 -0
- package/dist/commonjs/app/extend/context.js +279 -0
- package/dist/commonjs/app/middleware/multipart.d.ts +4 -0
- package/dist/commonjs/app/middleware/multipart.js +20 -0
- package/dist/commonjs/app/schedule/clean_tmpdir.d.ts +3 -0
- package/dist/commonjs/app/schedule/clean_tmpdir.js +58 -0
- package/dist/commonjs/app.d.ts +6 -0
- package/dist/commonjs/app.js +21 -0
- package/dist/commonjs/config/config.default.d.ts +98 -0
- package/dist/commonjs/config/config.default.js +31 -0
- package/dist/commonjs/index.d.ts +2 -0
- package/dist/commonjs/index.js +5 -0
- package/dist/commonjs/lib/LimitError.d.ts +5 -0
- package/dist/commonjs/lib/LimitError.js +16 -0
- package/dist/commonjs/lib/MultipartFileTooLargeError.d.ts +6 -0
- package/dist/commonjs/lib/MultipartFileTooLargeError.js +18 -0
- package/dist/commonjs/lib/utils.d.ts +4 -0
- package/dist/commonjs/lib/utils.js +93 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/esm/app/extend/context.d.ts +110 -0
- package/dist/esm/app/extend/context.js +273 -0
- package/dist/esm/app/middleware/multipart.d.ts +4 -0
- package/dist/esm/app/middleware/multipart.js +18 -0
- package/dist/esm/app/schedule/clean_tmpdir.d.ts +3 -0
- package/dist/esm/app/schedule/clean_tmpdir.js +53 -0
- package/dist/esm/app.d.ts +6 -0
- package/dist/esm/app.js +18 -0
- package/dist/esm/config/config.default.d.ts +98 -0
- package/dist/esm/config/config.default.js +26 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/lib/LimitError.d.ts +5 -0
- package/dist/esm/lib/LimitError.js +12 -0
- package/dist/esm/lib/MultipartFileTooLargeError.d.ts +6 -0
- package/dist/esm/lib/MultipartFileTooLargeError.js +14 -0
- package/dist/esm/lib/utils.d.ts +4 -0
- package/dist/esm/lib/utils.js +85 -0
- package/dist/esm/package.json +3 -0
- package/dist/package.json +4 -0
- package/package.json +103 -0
- package/src/app/extend/context.ts +368 -0
- package/src/app/middleware/multipart.ts +20 -0
- package/src/app/schedule/clean_tmpdir.ts +55 -0
- package/src/app.ts +20 -0
- package/src/config/config.default.ts +130 -0
- package/src/index.ts +2 -0
- package/src/lib/LimitError.ts +12 -0
- package/src/lib/MultipartFileTooLargeError.ts +14 -0
- package/src/lib/utils.ts +92 -0
- package/src/typings/index.d.ts +4 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.whitelist = void 0;
|
|
7
|
+
exports.humanizeBytes = humanizeBytes;
|
|
8
|
+
exports.normalizeOptions = normalizeOptions;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
11
|
+
const bytes_1 = __importDefault(require("bytes"));
|
|
12
|
+
exports.whitelist = [
|
|
13
|
+
// images
|
|
14
|
+
'.jpg', '.jpeg', // image/jpeg
|
|
15
|
+
'.png', // image/png, image/x-png
|
|
16
|
+
'.gif', // image/gif
|
|
17
|
+
'.bmp', // image/bmp
|
|
18
|
+
'.wbmp', // image/vnd.wap.wbmp
|
|
19
|
+
'.webp',
|
|
20
|
+
'.tif',
|
|
21
|
+
'.psd',
|
|
22
|
+
// text
|
|
23
|
+
'.svg',
|
|
24
|
+
'.js', '.jsx',
|
|
25
|
+
'.json',
|
|
26
|
+
'.css', '.less',
|
|
27
|
+
'.html', '.htm',
|
|
28
|
+
'.xml',
|
|
29
|
+
// tar
|
|
30
|
+
'.zip',
|
|
31
|
+
'.gz', '.tgz', '.gzip',
|
|
32
|
+
// video
|
|
33
|
+
'.mp3',
|
|
34
|
+
'.mp4',
|
|
35
|
+
'.avi',
|
|
36
|
+
];
|
|
37
|
+
function humanizeBytes(size) {
|
|
38
|
+
if (typeof size === 'number') {
|
|
39
|
+
return size;
|
|
40
|
+
}
|
|
41
|
+
return (0, bytes_1.default)(size);
|
|
42
|
+
}
|
|
43
|
+
function normalizeOptions(options) {
|
|
44
|
+
// make sure to cast the value of config **Size to number
|
|
45
|
+
options.fileSize = humanizeBytes(options.fileSize);
|
|
46
|
+
options.fieldSize = humanizeBytes(options.fieldSize);
|
|
47
|
+
options.fieldNameSize = humanizeBytes(options.fieldNameSize);
|
|
48
|
+
// validate mode
|
|
49
|
+
options.mode = options.mode || 'stream';
|
|
50
|
+
(0, node_assert_1.default)(['stream', 'file'].includes(options.mode), `Expect mode to be 'stream' or 'file', but got '${options.mode}'`);
|
|
51
|
+
if (options.mode === 'file') {
|
|
52
|
+
(0, node_assert_1.default)(!options.fileModeMatch, '`fileModeMatch` options only work on stream mode, please remove it');
|
|
53
|
+
}
|
|
54
|
+
// normalize whitelist
|
|
55
|
+
if (Array.isArray(options.whitelist)) {
|
|
56
|
+
options.whitelist = options.whitelist.map(extname => extname.toLowerCase());
|
|
57
|
+
}
|
|
58
|
+
// normalize fileExtensions
|
|
59
|
+
if (Array.isArray(options.fileExtensions)) {
|
|
60
|
+
options.fileExtensions = options.fileExtensions.map(extname => {
|
|
61
|
+
return (extname.startsWith('.') || extname === '') ? extname.toLowerCase() : `.${extname.toLowerCase()}`;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function checkExt(fileName) {
|
|
65
|
+
if (typeof options.whitelist === 'function') {
|
|
66
|
+
return options.whitelist(fileName);
|
|
67
|
+
}
|
|
68
|
+
const extname = node_path_1.default.extname(fileName).toLowerCase();
|
|
69
|
+
if (Array.isArray(options.whitelist)) {
|
|
70
|
+
return options.whitelist.includes(extname);
|
|
71
|
+
}
|
|
72
|
+
// only if user don't provide whitelist, we will use default whitelist + fileExtensions
|
|
73
|
+
return exports.whitelist.includes(extname) || options.fileExtensions.includes(extname);
|
|
74
|
+
}
|
|
75
|
+
options.checkFile = (_fieldName, fileStream, fileName) => {
|
|
76
|
+
// just ignore, if no file
|
|
77
|
+
if (!fileStream || !fileName)
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
if (!checkExt(fileName)) {
|
|
81
|
+
const err = new Error('Invalid filename: ' + fileName);
|
|
82
|
+
Reflect.set(err, 'status', 400);
|
|
83
|
+
return err;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
err.status = 400;
|
|
88
|
+
return err;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
return options;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQStCQSxzQ0FLQztBQUVELDRDQXFEQztBQTNGRCwwREFBNkI7QUFDN0IsOERBQWlDO0FBQ2pDLGtEQUEwQjtBQUdiLFFBQUEsU0FBUyxHQUFHO0lBQ3ZCLFNBQVM7SUFDVCxNQUFNLEVBQUUsT0FBTyxFQUFFLGFBQWE7SUFDOUIsTUFBTSxFQUFFLHlCQUF5QjtJQUNqQyxNQUFNLEVBQUUsWUFBWTtJQUNwQixNQUFNLEVBQUUsWUFBWTtJQUNwQixPQUFPLEVBQUUscUJBQXFCO0lBQzlCLE9BQU87SUFDUCxNQUFNO0lBQ04sTUFBTTtJQUNOLE9BQU87SUFDUCxNQUFNO0lBQ04sS0FBSyxFQUFFLE1BQU07SUFDYixPQUFPO0lBQ1AsTUFBTSxFQUFFLE9BQU87SUFDZixPQUFPLEVBQUUsTUFBTTtJQUNmLE1BQU07SUFDTixNQUFNO0lBQ04sTUFBTTtJQUNOLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTztJQUN0QixRQUFRO0lBQ1IsTUFBTTtJQUNOLE1BQU07SUFDTixNQUFNO0NBQ1AsQ0FBQztBQUVGLFNBQWdCLGFBQWEsQ0FBQyxJQUFxQjtJQUNqRCxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzdCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUNELE9BQU8sSUFBQSxlQUFLLEVBQUMsSUFBSSxDQUFXLENBQUM7QUFDL0IsQ0FBQztBQUVELFNBQWdCLGdCQUFnQixDQUFDLE9BQXdCO0lBQ3ZELHlEQUF5RDtJQUN6RCxPQUFPLENBQUMsUUFBUSxHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDbkQsT0FBTyxDQUFDLFNBQVMsR0FBRyxhQUFhLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3JELE9BQU8sQ0FBQyxhQUFhLEdBQUcs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
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { Context } from '@eggjs/core';
|
|
3
|
+
export interface EggFile {
|
|
4
|
+
field: string;
|
|
5
|
+
filename: string;
|
|
6
|
+
encoding: string;
|
|
7
|
+
mime: string;
|
|
8
|
+
filepath: string;
|
|
9
|
+
}
|
|
10
|
+
export interface MultipartFileStream extends Readable {
|
|
11
|
+
fields: Record<string, any>;
|
|
12
|
+
filename: string;
|
|
13
|
+
fieldname: string;
|
|
14
|
+
mime: string;
|
|
15
|
+
mimeType: string;
|
|
16
|
+
transferEncoding: string;
|
|
17
|
+
encoding: string;
|
|
18
|
+
truncated: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface MultipartOptions {
|
|
21
|
+
autoFields?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* required file submit, default is true
|
|
24
|
+
*/
|
|
25
|
+
requireFile?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* default charset encoding
|
|
28
|
+
*/
|
|
29
|
+
defaultCharset?: string;
|
|
30
|
+
/**
|
|
31
|
+
* compatible with defaultCharset
|
|
32
|
+
* @deprecated use `defaultCharset` instead
|
|
33
|
+
*/
|
|
34
|
+
defCharset?: string;
|
|
35
|
+
defaultParamCharset?: string;
|
|
36
|
+
/**
|
|
37
|
+
* compatible with defaultParamCharset
|
|
38
|
+
* @deprecated use `defaultParamCharset` instead
|
|
39
|
+
*/
|
|
40
|
+
defParamCharset?: string;
|
|
41
|
+
limits?: {
|
|
42
|
+
fieldNameSize?: number;
|
|
43
|
+
fieldSize?: number;
|
|
44
|
+
fields?: number;
|
|
45
|
+
fileSize?: number;
|
|
46
|
+
files?: number;
|
|
47
|
+
parts?: number;
|
|
48
|
+
headerPairs?: number;
|
|
49
|
+
};
|
|
50
|
+
checkFile?(fieldname: string, file: any, filename: string, encoding: string, mimetype: string): void | Error;
|
|
51
|
+
}
|
|
52
|
+
export default class MultipartContext extends Context {
|
|
53
|
+
/**
|
|
54
|
+
* create multipart.parts instance, to get separated files.
|
|
55
|
+
* @function Context#multipart
|
|
56
|
+
* @param {Object} [options] - override default multipart configurations
|
|
57
|
+
* - {Boolean} options.autoFields
|
|
58
|
+
* - {String} options.defaultCharset
|
|
59
|
+
* - {String} options.defaultParamCharset
|
|
60
|
+
* - {Object} options.limits
|
|
61
|
+
* - {Function} options.checkFile
|
|
62
|
+
* @return {Yieldable | AsyncIterable<Yieldable>} parts
|
|
63
|
+
*/
|
|
64
|
+
multipart(options?: MultipartOptions): AsyncIterable<MultipartFileStream>;
|
|
65
|
+
/**
|
|
66
|
+
* save request multipart data and files to `ctx.request`
|
|
67
|
+
* @function Context#saveRequestFiles
|
|
68
|
+
* @param {Object} options - { limits, checkFile, ... }
|
|
69
|
+
*/
|
|
70
|
+
saveRequestFiles(options?: MultipartOptions): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* get upload file stream
|
|
73
|
+
* @example
|
|
74
|
+
* ```js
|
|
75
|
+
* const stream = await ctx.getFileStream();
|
|
76
|
+
* // get other fields
|
|
77
|
+
* console.log(stream.fields);
|
|
78
|
+
* ```
|
|
79
|
+
* @function Context#getFileStream
|
|
80
|
+
* @param {Object} options
|
|
81
|
+
* - {Boolean} options.requireFile - required file submit, default is true
|
|
82
|
+
* - {String} options.defaultCharset
|
|
83
|
+
* - {String} options.defaultParamCharset
|
|
84
|
+
* - {Object} options.limits
|
|
85
|
+
* - {Function} options.checkFile
|
|
86
|
+
* @return {ReadStream} stream
|
|
87
|
+
* @since 1.0.0
|
|
88
|
+
* @deprecated Not safe enough, use `ctx.multipart()` instead
|
|
89
|
+
*/
|
|
90
|
+
getFileStream(options?: MultipartOptions): Promise<MultipartFileStream>;
|
|
91
|
+
/**
|
|
92
|
+
* clean up request tmp files helper
|
|
93
|
+
* @function Context#cleanupRequestFiles
|
|
94
|
+
* @param {Array<String>} [files] - file paths need to cleanup, default is `ctx.request.files`.
|
|
95
|
+
*/
|
|
96
|
+
cleanupRequestFiles(files?: EggFile[]): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
declare module '@eggjs/core' {
|
|
99
|
+
interface Request {
|
|
100
|
+
/**
|
|
101
|
+
* Files Object Array
|
|
102
|
+
*/
|
|
103
|
+
files?: EggFile[];
|
|
104
|
+
}
|
|
105
|
+
interface Context {
|
|
106
|
+
saveRequestFiles(options?: MultipartOptions): Promise<void>;
|
|
107
|
+
getFileStream(options?: MultipartOptions): Promise<MultipartFileStream>;
|
|
108
|
+
cleanupRequestFiles(files?: EggFile[]): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import { createWriteStream } from 'node:fs';
|
|
6
|
+
import { Readable, PassThrough } from 'node:stream';
|
|
7
|
+
import { pipeline } from 'node:stream/promises';
|
|
8
|
+
// @ts-expect-error no types
|
|
9
|
+
import parse from 'co-busboy';
|
|
10
|
+
import dayjs from 'dayjs';
|
|
11
|
+
import { Context } from '@eggjs/core';
|
|
12
|
+
import { humanizeBytes } from '../../lib/utils.js';
|
|
13
|
+
import { LimitError } from '../../lib/LimitError.js';
|
|
14
|
+
import { MultipartFileTooLargeError } from '../../lib/MultipartFileTooLargeError.js';
|
|
15
|
+
const HAS_CONSUMED = Symbol('Context#multipartHasConsumed');
|
|
16
|
+
export default class MultipartContext extends Context {
|
|
17
|
+
/**
|
|
18
|
+
* create multipart.parts instance, to get separated files.
|
|
19
|
+
* @function Context#multipart
|
|
20
|
+
* @param {Object} [options] - override default multipart configurations
|
|
21
|
+
* - {Boolean} options.autoFields
|
|
22
|
+
* - {String} options.defaultCharset
|
|
23
|
+
* - {String} options.defaultParamCharset
|
|
24
|
+
* - {Object} options.limits
|
|
25
|
+
* - {Function} options.checkFile
|
|
26
|
+
* @return {Yieldable | AsyncIterable<Yieldable>} parts
|
|
27
|
+
*/
|
|
28
|
+
multipart(options = {}) {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
30
|
+
const ctx = this;
|
|
31
|
+
// multipart/form-data
|
|
32
|
+
if (!ctx.is('multipart'))
|
|
33
|
+
ctx.throw(400, 'Content-Type must be multipart/*');
|
|
34
|
+
assert(!ctx[HAS_CONSUMED], 'the multipart request can\'t be consumed twice');
|
|
35
|
+
ctx[HAS_CONSUMED] = true;
|
|
36
|
+
const { autoFields, defaultCharset, defaultParamCharset, checkFile } = ctx.app.config.multipart;
|
|
37
|
+
const { fieldNameSize, fieldSize, fields, fileSize, files } = ctx.app.config.multipart;
|
|
38
|
+
options = extractOptions(options);
|
|
39
|
+
const parseOptions = Object.assign({
|
|
40
|
+
autoFields,
|
|
41
|
+
defCharset: defaultCharset,
|
|
42
|
+
defParamCharset: defaultParamCharset,
|
|
43
|
+
checkFile,
|
|
44
|
+
}, options);
|
|
45
|
+
// https://github.com/mscdex/busboy#busboy-methods
|
|
46
|
+
// merge limits
|
|
47
|
+
parseOptions.limits = Object.assign({
|
|
48
|
+
fieldNameSize,
|
|
49
|
+
fieldSize,
|
|
50
|
+
fields,
|
|
51
|
+
fileSize,
|
|
52
|
+
files,
|
|
53
|
+
}, options.limits);
|
|
54
|
+
// mount asyncIterator, so we can use `for await` to get parts
|
|
55
|
+
const parts = parse(this, parseOptions);
|
|
56
|
+
parts[Symbol.asyncIterator] = async function* () {
|
|
57
|
+
let part;
|
|
58
|
+
do {
|
|
59
|
+
part = await parts();
|
|
60
|
+
if (!part)
|
|
61
|
+
continue;
|
|
62
|
+
if (Array.isArray(part)) {
|
|
63
|
+
if (part[3])
|
|
64
|
+
throw new LimitError('Request_fieldSize_limit', 'Reach fieldSize limit');
|
|
65
|
+
// TODO: still not support at busboy 1.x (only support at urlencoded)
|
|
66
|
+
// https://github.com/mscdex/busboy/blob/v0.3.1/lib/types/multipart.js#L5
|
|
67
|
+
// https://github.com/mscdex/busboy/blob/master/lib/types/multipart.js#L251
|
|
68
|
+
// if (part[2]) throw new LimitError('Request_fieldNameSize_limit', 'Reach fieldNameSize limit');
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// user click `upload` before choose a file, `part` will be file stream, but `part.filename` is empty must handler this, such as log error.
|
|
72
|
+
if (!part.filename) {
|
|
73
|
+
ctx.coreLogger.debug('[egg-multipart] file field `%s` is upload without file stream, will drop it.', part.fieldname);
|
|
74
|
+
await pipeline(part, new PassThrough());
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// TODO: check whether filename is malicious input
|
|
78
|
+
// busboy only set truncated when consume the stream
|
|
79
|
+
if (part.truncated) {
|
|
80
|
+
// in case of emit 'limit' too fast
|
|
81
|
+
throw new LimitError('Request_fileSize_limit', 'Reach fileSize limit');
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
part.once('limit', function () {
|
|
85
|
+
this.emit('error', new LimitError('Request_fileSize_limit', 'Reach fileSize limit'));
|
|
86
|
+
this.resume();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// dispatch part to outter logic such as for-await-of
|
|
91
|
+
yield part;
|
|
92
|
+
} while (part !== undefined);
|
|
93
|
+
};
|
|
94
|
+
return parts;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* save request multipart data and files to `ctx.request`
|
|
98
|
+
* @function Context#saveRequestFiles
|
|
99
|
+
* @param {Object} options - { limits, checkFile, ... }
|
|
100
|
+
*/
|
|
101
|
+
async saveRequestFiles(options = {}) {
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
103
|
+
const ctx = this;
|
|
104
|
+
const allowArrayField = ctx.app.config.multipart.allowArrayField;
|
|
105
|
+
let storeDir;
|
|
106
|
+
const requestBody = {};
|
|
107
|
+
const requestFiles = [];
|
|
108
|
+
options.autoFields = false;
|
|
109
|
+
const parts = ctx.multipart(options);
|
|
110
|
+
try {
|
|
111
|
+
for await (const part of parts) {
|
|
112
|
+
if (Array.isArray(part)) {
|
|
113
|
+
// fields
|
|
114
|
+
const [fieldName, fieldValue] = part;
|
|
115
|
+
if (!allowArrayField) {
|
|
116
|
+
requestBody[fieldName] = fieldValue;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
if (!requestBody[fieldName]) {
|
|
120
|
+
requestBody[fieldName] = fieldValue;
|
|
121
|
+
}
|
|
122
|
+
else if (!Array.isArray(requestBody[fieldName])) {
|
|
123
|
+
requestBody[fieldName] = [requestBody[fieldName], fieldValue];
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
requestBody[fieldName].push(fieldValue);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// stream
|
|
132
|
+
const { filename, fieldname, encoding, mime } = part;
|
|
133
|
+
if (!storeDir) {
|
|
134
|
+
// ${tmpdir}/YYYY/MM/DD/HH
|
|
135
|
+
storeDir = path.join(ctx.app.config.multipart.tmpdir, dayjs().format('YYYY/MM/DD/HH'));
|
|
136
|
+
await fs.mkdir(storeDir, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
// write to tmp file
|
|
139
|
+
const filepath = path.join(storeDir, randomUUID() + path.extname(filename));
|
|
140
|
+
const target = createWriteStream(filepath);
|
|
141
|
+
await pipeline(part, target);
|
|
142
|
+
const meta = {
|
|
143
|
+
filepath,
|
|
144
|
+
field: fieldname,
|
|
145
|
+
filename,
|
|
146
|
+
encoding,
|
|
147
|
+
mime,
|
|
148
|
+
// keep same property name as file stream, https://github.com/cojs/busboy/blob/master/index.js#L114
|
|
149
|
+
fieldname,
|
|
150
|
+
transferEncoding: encoding,
|
|
151
|
+
mimeType: mime,
|
|
152
|
+
};
|
|
153
|
+
requestFiles.push(meta);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
await ctx.cleanupRequestFiles(requestFiles);
|
|
159
|
+
throw err;
|
|
160
|
+
}
|
|
161
|
+
ctx.request.body = requestBody;
|
|
162
|
+
ctx.request.files = requestFiles;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* get upload file stream
|
|
166
|
+
* @example
|
|
167
|
+
* ```js
|
|
168
|
+
* const stream = await ctx.getFileStream();
|
|
169
|
+
* // get other fields
|
|
170
|
+
* console.log(stream.fields);
|
|
171
|
+
* ```
|
|
172
|
+
* @function Context#getFileStream
|
|
173
|
+
* @param {Object} options
|
|
174
|
+
* - {Boolean} options.requireFile - required file submit, default is true
|
|
175
|
+
* - {String} options.defaultCharset
|
|
176
|
+
* - {String} options.defaultParamCharset
|
|
177
|
+
* - {Object} options.limits
|
|
178
|
+
* - {Function} options.checkFile
|
|
179
|
+
* @return {ReadStream} stream
|
|
180
|
+
* @since 1.0.0
|
|
181
|
+
* @deprecated Not safe enough, use `ctx.multipart()` instead
|
|
182
|
+
*/
|
|
183
|
+
async getFileStream(options = {}) {
|
|
184
|
+
options.autoFields = true;
|
|
185
|
+
const parts = this.multipart(options);
|
|
186
|
+
let stream = await parts();
|
|
187
|
+
if (options.requireFile !== false) {
|
|
188
|
+
// stream not exists, treat as an exception
|
|
189
|
+
if (!stream || !stream.filename) {
|
|
190
|
+
this.throw(400, 'Can\'t found upload file');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (!stream) {
|
|
194
|
+
stream = Readable.from([]);
|
|
195
|
+
}
|
|
196
|
+
if (stream.truncated) {
|
|
197
|
+
throw new LimitError('Request_fileSize_limit', 'Request file too large, please check multipart config');
|
|
198
|
+
}
|
|
199
|
+
stream.fields = parts.field;
|
|
200
|
+
stream.once('limit', () => {
|
|
201
|
+
const err = new MultipartFileTooLargeError('Request file too large, please check multipart config', stream.fields, stream.filename);
|
|
202
|
+
if (stream.listenerCount('error') > 0) {
|
|
203
|
+
stream.emit('error', err);
|
|
204
|
+
this.coreLogger.warn(err);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
this.coreLogger.error(err);
|
|
208
|
+
// ignore next error event
|
|
209
|
+
stream.on('error', () => { });
|
|
210
|
+
}
|
|
211
|
+
// ignore all data
|
|
212
|
+
stream.resume();
|
|
213
|
+
});
|
|
214
|
+
return stream;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* clean up request tmp files helper
|
|
218
|
+
* @function Context#cleanupRequestFiles
|
|
219
|
+
* @param {Array<String>} [files] - file paths need to cleanup, default is `ctx.request.files`.
|
|
220
|
+
*/
|
|
221
|
+
async cleanupRequestFiles(files) {
|
|
222
|
+
if (!files || !files.length) {
|
|
223
|
+
files = this.request.files;
|
|
224
|
+
}
|
|
225
|
+
if (Array.isArray(files)) {
|
|
226
|
+
for (const file of files) {
|
|
227
|
+
try {
|
|
228
|
+
await fs.rm(file.filepath, { force: true, recursive: true });
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
// warning log
|
|
232
|
+
this.coreLogger.warn('[egg-multipart-cleanupRequestFiles-error] file: %j, error: %s', file, err);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function extractOptions(options = {}) {
|
|
239
|
+
const opts = {};
|
|
240
|
+
if (typeof options.autoFields === 'boolean') {
|
|
241
|
+
opts.autoFields = options.autoFields;
|
|
242
|
+
}
|
|
243
|
+
if (options.limits) {
|
|
244
|
+
opts.limits = options.limits;
|
|
245
|
+
}
|
|
246
|
+
if (options.checkFile) {
|
|
247
|
+
opts.checkFile = options.checkFile;
|
|
248
|
+
}
|
|
249
|
+
if (options.defCharset) {
|
|
250
|
+
opts.defCharset = options.defCharset;
|
|
251
|
+
}
|
|
252
|
+
if (options.defParamCharset) {
|
|
253
|
+
opts.defParamCharset = options.defParamCharset;
|
|
254
|
+
}
|
|
255
|
+
// compatible with config names
|
|
256
|
+
if (options.defaultCharset) {
|
|
257
|
+
opts.defCharset = options.defaultCharset;
|
|
258
|
+
}
|
|
259
|
+
if (options.defaultParamCharset) {
|
|
260
|
+
opts.defParamCharset = options.defaultParamCharset;
|
|
261
|
+
}
|
|
262
|
+
// limits
|
|
263
|
+
if (options.limits) {
|
|
264
|
+
const limits = opts.limits = { ...options.limits };
|
|
265
|
+
for (const key in limits) {
|
|
266
|
+
if (key.endsWith('Size') && limits[key]) {
|
|
267
|
+
limits[key] = humanizeBytes(limits[key]);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return opts;
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hcHAvZXh0ZW5kL2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ2pDLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUM1QyxPQUFPLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNwRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDaEQsNEJBQTRCO0FBQzVCLE9BQU8sS0FBSyxNQUFNLFdBQVcsQ0FBQztBQUM5QixPQUFPLEtBQUssTUFBTSxPQUFPLENBQUM7QUFDMUIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JELE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHlDQUF5QyxDQUFDO0FBRXJGLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0FBNEQ1RCxNQUFNLENBQUMsT0FBTyxPQUFPLGdCQUFpQixTQUFRLE9BQU87SUFDbkQ7Ozs7Ozs7Ozs7T0FVRztJQUNILFNBQVMsQ0FBQyxVQUE0QixFQUFFO1FBQ3RDLDREQUE0RDtRQUM1RCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUM7UUFDakIsc0JBQXNCO1FBQ3RCLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQztZQUFFLEdBQUcsQ0FBQyxL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
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Context, Next, EggCore } from '@eggjs/core';
|
|
2
|
+
import type { MultipartConfig } from '../../config/config.default.js';
|
|
3
|
+
declare const _default: (options: MultipartConfig, _app: EggCore) => (ctx: Context, next: Next) => Promise<void>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { pathMatching } from 'egg-path-matching';
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3
|
+
export default (options, _app) => {
|
|
4
|
+
// normalize options
|
|
5
|
+
const matchFn = options.fileModeMatch && pathMatching({
|
|
6
|
+
match: options.fileModeMatch,
|
|
7
|
+
// pathToRegexpModule: app.options.pathToRegexpModule,
|
|
8
|
+
});
|
|
9
|
+
return async function multipart(ctx, next) {
|
|
10
|
+
if (!ctx.is('multipart'))
|
|
11
|
+
return next();
|
|
12
|
+
if (matchFn && !matchFn(ctx))
|
|
13
|
+
return next();
|
|
14
|
+
await ctx.saveRequestFiles();
|
|
15
|
+
return next();
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXVsdGlwYXJ0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FwcC9taWRkbGV3YXJlL211bHRpcGFydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFJakQsNkRBQTZEO0FBQzdELGVBQWUsQ0FBQyxPQUF3QixFQUFFLElBQWEsRUFBRSxFQUFFO0lBQ3pELG9CQUFvQjtJQUNwQixNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsYUFBYSxJQUFJLFlBQVksQ0FBQztRQUNwRCxLQUFLLEVBQUUsT0FBTyxDQUFDLGFBQWE7UUFDNUIsc0RBQXNEO0tBQ3ZELENBQUMsQ0FBQztJQUVILE9BQU8sS0FBSyxVQUFVLFNBQVMsQ0FBQyxHQUFZLEVBQUUsSUFBVTtRQUN0RCxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUM7WUFBRSxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ3hDLElBQUksT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUFFLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFFNUMsTUFBTSxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUM3QixPQUFPLElBQUksRUFBRSxDQUFDO0lBQ2hCLENBQUMsQ0FBQztBQUNKLENBQUMsQ0FBQyJ9
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
export default (app) => {
|
|
5
|
+
return class CleanTmpdir extends app.Subscription {
|
|
6
|
+
static get schedule() {
|
|
7
|
+
return {
|
|
8
|
+
type: 'worker',
|
|
9
|
+
cron: app.config.multipart.cleanSchedule.cron,
|
|
10
|
+
disable: app.config.multipart.cleanSchedule.disable,
|
|
11
|
+
immediate: false,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async _remove(dir) {
|
|
15
|
+
const { ctx } = this;
|
|
16
|
+
if (await fs.access(dir).then(() => true, () => false)) {
|
|
17
|
+
ctx.coreLogger.info('[@eggjs/multipart:CleanTmpdir] removing tmpdir: %j', dir);
|
|
18
|
+
try {
|
|
19
|
+
await fs.rm(dir, { force: true, recursive: true });
|
|
20
|
+
ctx.coreLogger.info('[@eggjs/multipart:CleanTmpdir:success] tmpdir: %j has been removed', dir);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
/* c8 ignore next 3 */
|
|
24
|
+
ctx.coreLogger.error('[@eggjs/multipart:CleanTmpdir:error] remove tmpdir: %j error: %s', dir, err);
|
|
25
|
+
ctx.coreLogger.error(err);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async subscribe() {
|
|
30
|
+
const { ctx } = this;
|
|
31
|
+
const config = ctx.app.config;
|
|
32
|
+
ctx.coreLogger.info('[@eggjs/multipart:CleanTmpdir] start clean tmpdir: %j', config.multipart.tmpdir);
|
|
33
|
+
// last year
|
|
34
|
+
const lastYear = dayjs().subtract(1, 'years');
|
|
35
|
+
const lastYearDir = path.join(config.multipart.tmpdir, lastYear.format('YYYY'));
|
|
36
|
+
await this._remove(lastYearDir);
|
|
37
|
+
// 3 months
|
|
38
|
+
for (let i = 1; i <= 3; i++) {
|
|
39
|
+
const date = dayjs().subtract(i, 'months');
|
|
40
|
+
const dir = path.join(config.multipart.tmpdir, date.format('YYYY/MM'));
|
|
41
|
+
await this._remove(dir);
|
|
42
|
+
}
|
|
43
|
+
// 7 days
|
|
44
|
+
for (let i = 1; i <= 7; i++) {
|
|
45
|
+
const date = dayjs().subtract(i, 'days');
|
|
46
|
+
const dir = path.join(config.multipart.tmpdir, date.format('YYYY/MM/DD'));
|
|
47
|
+
await this._remove(dir);
|
|
48
|
+
}
|
|
49
|
+
ctx.coreLogger.info('[@eggjs/multipart:CleanTmpdir] end');
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xlYW5fdG1wZGlyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FwcC9zY2hlZHVsZS9jbGVhbl90bXBkaXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUcxQixlQUFlLENBQUMsR0FBWSxFQUFPLEVBQUU7SUFDbkMsT0FBTyxNQUFNLFdBQVksU0FBUSxHQUFHLENBQUMsWUFBWTtRQUMvQyxNQUFNLEtBQUssUUFBUTtZQUNqQixPQUFPO2dCQUNMLElBQUksRUFBRSxRQUFRO2dCQUNkLElBQUksRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsSUFBSTtnQkFDN0MsT0FBTyxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxPQUFPO2dCQUNuRCxTQUFTLEVBQUUsS0FBSzthQUNqQixDQUFDO1FBQ0osQ0FBQztRQUVELEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBVztZQUN2QixNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO1lBQ3JCLElBQUksTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDdkQsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsb0RBQW9ELEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQy9FLElBQUksQ0FBQztvQkFDSCxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDbkQsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsb0VBQW9FLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQ2pHLENBQUM7Z0JBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztvQkFDYixzQkFBc0I7b0JBQ3RCLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLGtFQUFrRSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDbkcsR0FBRyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzVCLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELEtBQUssQ0FBQyxTQUFTO1lBQ2IsTUFBTSxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztZQUNyQixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQztZQUM5QixHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyx1REFBdUQsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3RHLFlBQVk7WUFDWixNQUFNLFFBQVEsR0FBRyxLQUFLLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQzlDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1lBQ2hGLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUNoQyxXQUFXO1lBQ1gsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUM1QixNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUMzQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztnQkFDdkUsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzFCLENBQUM7WUFDRCxTQUFTO1lBQ1QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUM1QixNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUN6QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQztnQkFDMUUsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzFCLENBQUM7WUFDRCxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDO1FBQzVELENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyxDQUFDIn0=
|
package/dist/esm/app.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { normalizeOptions } from './lib/utils.js';
|
|
2
|
+
export default class AppBootHook {
|
|
3
|
+
app;
|
|
4
|
+
constructor(app) {
|
|
5
|
+
this.app = app;
|
|
6
|
+
}
|
|
7
|
+
configWillLoad() {
|
|
8
|
+
this.app.config.multipart = normalizeOptions(this.app.config.multipart);
|
|
9
|
+
const options = this.app.config.multipart;
|
|
10
|
+
this.app.coreLogger.info('[@eggjs/multipart] %s mode enable', options.mode);
|
|
11
|
+
if (options.mode === 'file' || options.fileModeMatch) {
|
|
12
|
+
this.app.coreLogger.info('[@eggjs/multipart] will save temporary files to %j, cleanup job cron: %j', options.tmpdir, options.cleanSchedule.cron);
|
|
13
|
+
// enable multipart middleware
|
|
14
|
+
this.app.config.coreMiddleware.push('multipart');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVsRCxNQUFNLENBQUMsT0FBTyxPQUFPLFdBQVc7SUFDVjtJQUFwQixZQUFvQixHQUFZO1FBQVosUUFBRyxHQUFILEdBQUcsQ0FBUztJQUFHLENBQUM7SUFFcEMsY0FBYztRQUNaLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN4RSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFFMUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLG1DQUFtQyxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM1RSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNyRCxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsMEVBQTBFLEVBQ2pHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM5Qyw4QkFBOEI7WUFDOUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuRCxDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
|