@midwayjs/upload 3.0.0-beta.9

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/CHANGELOG.md ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ import { UploadOptions } from '../interface';
2
+ export declare const upload: UploadOptions;
3
+ //# sourceMappingURL=config.default.d.ts.map
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.upload = void 0;
4
+ const interface_1 = require("../interface");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ exports.upload = {
8
+ mode: interface_1.UploadMode.File,
9
+ fileSize: '10mb',
10
+ whitelist: [
11
+ // images
12
+ '.jpg',
13
+ '.jpeg',
14
+ '.png',
15
+ '.gif',
16
+ '.bmp',
17
+ '.wbmp',
18
+ '.webp',
19
+ '.tif',
20
+ '.psd',
21
+ // text
22
+ '.svg',
23
+ '.js',
24
+ '.jsx',
25
+ '.json',
26
+ '.css',
27
+ '.less',
28
+ '.html',
29
+ '.htm',
30
+ '.xml',
31
+ '.pdf',
32
+ // tar
33
+ '.zip',
34
+ '.gz',
35
+ '.tgz',
36
+ '.gzip',
37
+ // video
38
+ '.mp3',
39
+ '.mp4',
40
+ '.avi',
41
+ ],
42
+ tmpdir: (0, path_1.join)((0, os_1.tmpdir)(), 'midway-upload-files'),
43
+ };
44
+ //# sourceMappingURL=config.default.js.map
@@ -0,0 +1,7 @@
1
+ import { MidwayApplicationManager } from '@midwayjs/core';
2
+ export declare class UploadConfiguration {
3
+ applicationManager: MidwayApplicationManager;
4
+ uploadConfig: any;
5
+ onReady(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=configuration.d.ts.map
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.UploadConfiguration = void 0;
13
+ const decorator_1 = require("@midwayjs/decorator");
14
+ const DefaultConfig = require("./config/config.default");
15
+ const core_1 = require("@midwayjs/core");
16
+ const middleware_1 = require("./middleware");
17
+ const fs_extra_1 = require("fs-extra");
18
+ let UploadConfiguration = class UploadConfiguration {
19
+ async onReady() {
20
+ const { tmpdir } = this.uploadConfig;
21
+ if (tmpdir) {
22
+ await (0, fs_extra_1.ensureDir)(tmpdir);
23
+ }
24
+ this.applicationManager
25
+ .getApplications(['koa', 'faas', 'express', 'egg'])
26
+ .forEach(app => {
27
+ app.useMiddleware(middleware_1.UploadMiddleware);
28
+ });
29
+ }
30
+ };
31
+ __decorate([
32
+ (0, decorator_1.Inject)(),
33
+ __metadata("design:type", core_1.MidwayApplicationManager)
34
+ ], UploadConfiguration.prototype, "applicationManager", void 0);
35
+ __decorate([
36
+ (0, decorator_1.Config)('upload'),
37
+ __metadata("design:type", Object)
38
+ ], UploadConfiguration.prototype, "uploadConfig", void 0);
39
+ UploadConfiguration = __decorate([
40
+ (0, decorator_1.Configuration)({
41
+ namespace: 'upload',
42
+ importConfigs: [
43
+ {
44
+ default: DefaultConfig,
45
+ },
46
+ ],
47
+ })
48
+ ], UploadConfiguration);
49
+ exports.UploadConfiguration = UploadConfiguration;
50
+ //# sourceMappingURL=configuration.js.map
@@ -0,0 +1,4 @@
1
+ export { UploadConfiguration as Configuration } from './configuration';
2
+ export * from './interface';
3
+ export * from './middleware';
4
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.Configuration = void 0;
14
+ var configuration_1 = require("./configuration");
15
+ Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return configuration_1.UploadConfiguration; } });
16
+ __exportStar(require("./interface"), exports);
17
+ __exportStar(require("./middleware"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,20 @@
1
+ /// <reference types="node" />
2
+ import { Readable } from "stream";
3
+ export declare enum UploadMode {
4
+ Stream = "stream",
5
+ File = "file",
6
+ Buffer = "buffer"
7
+ }
8
+ export interface UploadOptions {
9
+ mode?: UploadMode;
10
+ fileSize?: string;
11
+ whitelist?: string[];
12
+ tmpdir?: string;
13
+ }
14
+ export interface UploadFileInfo {
15
+ filename: string;
16
+ fieldname: string;
17
+ mimeType: string;
18
+ data: Buffer | Readable | string;
19
+ }
20
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UploadMode = void 0;
4
+ var UploadMode;
5
+ (function (UploadMode) {
6
+ UploadMode["Stream"] = "stream";
7
+ UploadMode["File"] = "file";
8
+ UploadMode["Buffer"] = "buffer";
9
+ })(UploadMode = exports.UploadMode || (exports.UploadMode = {}));
10
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1,12 @@
1
+ import { IMiddleware, IMidwayLogger } from '@midwayjs/core';
2
+ import { UploadOptions } from '.';
3
+ export declare class UploadMiddleware implements IMiddleware<any, any> {
4
+ upload: UploadOptions;
5
+ logger: IMidwayLogger;
6
+ resolve(app: any): (req: any, res: any, next: any) => Promise<any>;
7
+ execUpload(ctx: any, req: any, res: any, next: any, isExpress: any): Promise<any>;
8
+ getUploadBoundary(request: any): false | string;
9
+ isReadableStream(req: any, isExpress: any): boolean;
10
+ checkExt(filename: any): boolean;
11
+ }
12
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.UploadMiddleware = void 0;
13
+ const decorator_1 = require("@midwayjs/decorator");
14
+ const path_1 = require("path");
15
+ const fs_1 = require("fs");
16
+ const stream_1 = require("stream");
17
+ const _1 = require(".");
18
+ const upload_1 = require("./upload");
19
+ const getRawBody = require("raw-body");
20
+ let UploadMiddleware = class UploadMiddleware {
21
+ resolve(app) {
22
+ if (app.getFrameworkType() === decorator_1.MidwayFrameworkType.WEB_EXPRESS) {
23
+ return async (req, res, next) => {
24
+ return this.execUpload(req, req, res, next, true);
25
+ };
26
+ }
27
+ else {
28
+ return async (ctx, next) => {
29
+ var _a;
30
+ const req = ((_a = ctx.request) === null || _a === void 0 ? void 0 : _a.req) || ctx.request;
31
+ return this.execUpload(ctx, req, ctx, next, false);
32
+ };
33
+ }
34
+ }
35
+ async execUpload(ctx, req, res, next, isExpress) {
36
+ const { mode, tmpdir, fileSize } = this.upload;
37
+ const boundary = this.getUploadBoundary(req);
38
+ if (!boundary) {
39
+ return next();
40
+ }
41
+ ctx.fields = {};
42
+ let body;
43
+ if (this.isReadableStream(req, isExpress)) {
44
+ if (mode === _1.UploadMode.Stream) {
45
+ const { fields, fileInfo } = await (0, upload_1.parseFromReadableStream)(req, boundary);
46
+ if (!this.checkExt(fileInfo.filename)) {
47
+ res.status = 400;
48
+ const errorMessage = 'Invalid filename: ' + fileInfo.filename;
49
+ const err = new Error(errorMessage);
50
+ this.logger.error(err);
51
+ if (isExpress) {
52
+ return res.sendStatus(400);
53
+ }
54
+ return;
55
+ }
56
+ else {
57
+ ctx.fields = fields;
58
+ ctx.files = [fileInfo];
59
+ return next();
60
+ }
61
+ }
62
+ body = await getRawBody(req, {
63
+ limit: fileSize,
64
+ });
65
+ }
66
+ else {
67
+ body = req.body;
68
+ }
69
+ const data = await (0, upload_1.parseMultipart)(body, boundary);
70
+ if (!data) {
71
+ return next();
72
+ }
73
+ ctx.fields = data.fields;
74
+ const requireId = `upload_${Date.now()}.${Math.random()}`;
75
+ const files = data.files;
76
+ const notCheckFile = files.find(fileInfo => {
77
+ if (!this.checkExt(fileInfo.filename)) {
78
+ return fileInfo;
79
+ }
80
+ });
81
+ if (notCheckFile) {
82
+ res.status = 400;
83
+ const errorMessage = 'Invalid filename: ' + notCheckFile.filename;
84
+ const err = new Error(errorMessage);
85
+ this.logger.error(err);
86
+ if (isExpress) {
87
+ return res.sendStatus(400);
88
+ }
89
+ return;
90
+ }
91
+ ctx.files =
92
+ mode === 'buffer'
93
+ ? files
94
+ : files.map((file, index) => {
95
+ const { data, filename } = file;
96
+ if (mode === _1.UploadMode.File) {
97
+ const ext = (0, path_1.extname)(filename);
98
+ const tmpFileName = (0, path_1.resolve)(tmpdir, `${requireId}.${index}${ext}`);
99
+ (0, fs_1.writeFileSync)(tmpFileName, data, 'binary');
100
+ file.data = tmpFileName;
101
+ }
102
+ else if (mode === _1.UploadMode.Stream) {
103
+ file.data = new stream_1.Readable({
104
+ read() {
105
+ this.push(data);
106
+ this.push(null);
107
+ },
108
+ });
109
+ }
110
+ return file;
111
+ });
112
+ return next();
113
+ }
114
+ getUploadBoundary(request) {
115
+ var _a;
116
+ const method = (request.method || request.httpMethod || '').toUpperCase();
117
+ if (!((_a = request.headers) === null || _a === void 0 ? void 0 : _a['content-type']) || method !== 'POST') {
118
+ return false;
119
+ }
120
+ const contentType = request.headers['content-type'];
121
+ if (!contentType.startsWith('multipart/form-data;')) {
122
+ return false;
123
+ }
124
+ const boundaryMatch = /boundary=(.*)(;|\s|$)/.exec(contentType);
125
+ if (!(boundaryMatch === null || boundaryMatch === void 0 ? void 0 : boundaryMatch[1])) {
126
+ return false;
127
+ }
128
+ return boundaryMatch[1];
129
+ }
130
+ isReadableStream(req, isExpress) {
131
+ // ref: https://github.com/rvagg/isstream/blob/master/isstream.js#L10
132
+ if (req instanceof stream_1.Stream &&
133
+ typeof req._read === 'function' &&
134
+ typeof req._readableState === 'object' &&
135
+ (!req.body || isExpress)) {
136
+ return true;
137
+ }
138
+ if (req.pipe && req.on && !req.body) {
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ checkExt(filename) {
144
+ const ext = (0, path_1.extname)(filename).toLowerCase();
145
+ const { whitelist } = this.upload;
146
+ if (!Array.isArray(whitelist)) {
147
+ return true;
148
+ }
149
+ return whitelist.includes(ext);
150
+ }
151
+ };
152
+ __decorate([
153
+ (0, decorator_1.Config)('upload'),
154
+ __metadata("design:type", Object)
155
+ ], UploadMiddleware.prototype, "upload", void 0);
156
+ __decorate([
157
+ (0, decorator_1.Logger)(),
158
+ __metadata("design:type", Object)
159
+ ], UploadMiddleware.prototype, "logger", void 0);
160
+ UploadMiddleware = __decorate([
161
+ (0, decorator_1.Middleware)()
162
+ ], UploadMiddleware);
163
+ exports.UploadMiddleware = UploadMiddleware;
164
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" />
2
+ import { Readable } from 'stream';
3
+ import { UploadFileInfo } from './interface';
4
+ export declare const parseMultipart: (body: any, boundary: string) => Promise<{
5
+ files: any[];
6
+ fields: {};
7
+ }>;
8
+ export declare const parseFromReadableStream: (readStream: Readable, boundary: any) => Promise<{
9
+ fields: any;
10
+ fileInfo: UploadFileInfo;
11
+ }>;
12
+ export declare const bufferIndexOf: (buffer: Buffer, search: Buffer, offset?: number) => number;
13
+ export declare const bufferSplit: (buffer: Buffer, separator: Buffer, limit?: number) => Buffer[];
14
+ export declare const parseHead: (headBuf: Buffer) => {};
15
+ //# sourceMappingURL=upload.d.ts.map
package/dist/upload.js ADDED
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseHead = exports.bufferSplit = exports.bufferIndexOf = exports.parseFromReadableStream = exports.parseMultipart = void 0;
4
+ const stream_1 = require("stream");
5
+ const headSeparator = Buffer.from('\r\n\r\n');
6
+ const parseMultipart = async (body, boundary) => {
7
+ if (typeof body === 'string') {
8
+ body = Buffer.from(body);
9
+ }
10
+ const bufferSeparator = Buffer.from('\r\n--' + boundary);
11
+ const fields = {};
12
+ const files = [];
13
+ (0, exports.bufferSplit)(body, bufferSeparator).forEach(buf => {
14
+ const [headerBuf, data] = (0, exports.bufferSplit)(buf, headSeparator, 2);
15
+ const head = (0, exports.parseHead)(headerBuf);
16
+ if (!head['content-disposition']) {
17
+ return;
18
+ }
19
+ if (!head['content-disposition'].filename) {
20
+ if (head['content-disposition'].name) {
21
+ fields[head['content-disposition'].name] = data.toString();
22
+ }
23
+ return;
24
+ }
25
+ files.push({
26
+ filename: head['content-disposition'].filename,
27
+ data,
28
+ fieldname: head['content-disposition'].name,
29
+ mimeType: head['content-type'],
30
+ });
31
+ });
32
+ return {
33
+ files,
34
+ fields,
35
+ };
36
+ };
37
+ exports.parseMultipart = parseMultipart;
38
+ const pre = Buffer.from('\r\n');
39
+ const parseFromReadableStream = (readStream, boundary) => {
40
+ const bufferSeparator = Buffer.from(`\r\n--${boundary}`);
41
+ const fields = {};
42
+ const fileInfo = {
43
+ filename: '',
44
+ data: null,
45
+ fieldname: '',
46
+ mimeType: '',
47
+ };
48
+ const emptyBuf = Buffer.alloc(0);
49
+ // 上一次遗留的 chunk
50
+ let lastChunk = emptyBuf;
51
+ // 前一个chunk的后缀
52
+ let preChunk = emptyBuf;
53
+ let isTransformFileData = false;
54
+ let isTransformFileDataEnd = false;
55
+ // let isEnd = false;
56
+ let isFirst = true;
57
+ let allChuns = Buffer.alloc(0);
58
+ return new Promise(resolve => {
59
+ fileInfo.data = new stream_1.Transform({
60
+ highWaterMark: 1000,
61
+ transform(chunk, encoding, callback) {
62
+ if (isFirst) {
63
+ chunk = Buffer.concat([pre, chunk]);
64
+ isFirst = false;
65
+ }
66
+ // 已经结束了
67
+ if (isTransformFileDataEnd) {
68
+ return callback(null, null);
69
+ }
70
+ // 正在传输中的话
71
+ if (isTransformFileData) {
72
+ if (lastChunk.length) {
73
+ chunk = Buffer.concat([lastChunk, chunk]);
74
+ lastChunk = emptyBuf;
75
+ }
76
+ const newPreChunk = Buffer.concat([preChunk, chunk]);
77
+ const newBlockIndex = (0, exports.bufferIndexOf)(newPreChunk, bufferSeparator);
78
+ // 存在新的块则代表已经结束了
79
+ if (newBlockIndex !== -1) {
80
+ // 上一个块的最后一部分数据,需要追加写入
81
+ const lastDataBlock = newPreChunk.slice(preChunk.length, newBlockIndex);
82
+ isTransformFileDataEnd = true;
83
+ callback(null, lastDataBlock);
84
+ return;
85
+ }
86
+ // 块尚未结束,则继续写入
87
+ callback(null, chunk);
88
+ preChunk = newPreChunk.slice(-bufferSeparator.length);
89
+ return;
90
+ }
91
+ // 未在传输过程中
92
+ allChuns = Buffer.concat([allChuns, chunk]);
93
+ const splitAllChuns = (0, exports.bufferSplit)(allChuns, bufferSeparator);
94
+ for (let chunkIndex = 0; chunkIndex < splitAllChuns.length; chunkIndex++) {
95
+ const [headerBuf, data] = (0, exports.bufferSplit)(splitAllChuns[chunkIndex], headSeparator);
96
+ const head = (0, exports.parseHead)(headerBuf);
97
+ if (!head['content-disposition']) {
98
+ continue;
99
+ }
100
+ if (!head['content-disposition'].filename) {
101
+ if (head['content-disposition'].name) {
102
+ fields[head['content-disposition'].name] = data.toString();
103
+ }
104
+ continue;
105
+ }
106
+ // 这里就是找到了 file 的段,如果没有数据,则需要继续等待
107
+ if (!data.length) {
108
+ continue;
109
+ }
110
+ fileInfo.filename = head['content-disposition'].filename;
111
+ fileInfo.fieldname = head['content-disposition'].name;
112
+ fileInfo.mimeType = head['content-type'];
113
+ isTransformFileData = true;
114
+ lastChunk = data;
115
+ allChuns = emptyBuf;
116
+ this.pause();
117
+ resolve({ fileInfo, fields });
118
+ break;
119
+ }
120
+ callback(null, emptyBuf);
121
+ },
122
+ });
123
+ readStream.pipe(fileInfo.data);
124
+ const empty = new stream_1.Writable();
125
+ empty._write = function (chunk, encoding, cb) {
126
+ cb();
127
+ };
128
+ fileInfo.data.pipe(empty);
129
+ });
130
+ };
131
+ exports.parseFromReadableStream = parseFromReadableStream;
132
+ // search buffer index
133
+ const bufferIndexOf = (buffer, search, offset) => {
134
+ return buffer.indexOf(search, offset);
135
+ };
136
+ exports.bufferIndexOf = bufferIndexOf;
137
+ // split buffer to buffer list
138
+ const bufferSplit = (buffer, separator, limit) => {
139
+ let index = 0;
140
+ const result = [];
141
+ let find = (0, exports.bufferIndexOf)(buffer, separator, index);
142
+ while (find !== -1) {
143
+ result.push(buffer.slice(index, find));
144
+ index = find + separator.length;
145
+ if (limit && result.length + 1 === limit) {
146
+ break;
147
+ }
148
+ find = (0, exports.bufferIndexOf)(buffer, separator, index);
149
+ }
150
+ result.push(buffer.slice(index));
151
+ return result;
152
+ };
153
+ exports.bufferSplit = bufferSplit;
154
+ const headReg = /^([^:]+):[ \t]?(.+)?$/;
155
+ const parseHead = (headBuf) => {
156
+ const head = {};
157
+ const headStrList = headBuf.toString().split('\r\n');
158
+ for (const headStr of headStrList) {
159
+ const matched = headReg.exec(headStr);
160
+ if (!matched) {
161
+ continue;
162
+ }
163
+ const name = matched[1].toLowerCase();
164
+ const value = matched[2]
165
+ ? matched[2].replace(/&#(\d+);/g, (origin, code) => {
166
+ try {
167
+ return String.fromCharCode(parseInt(code));
168
+ }
169
+ catch (_a) {
170
+ return origin;
171
+ }
172
+ })
173
+ : '';
174
+ if (name === 'content-disposition') {
175
+ const headCol = {};
176
+ value.split(/;\s+/).forEach((kv) => {
177
+ const [k, v] = kv.split('=');
178
+ headCol[k] = v ? v.replace(/^"/, '').replace(/"$/, '') : v !== null && v !== void 0 ? v : true;
179
+ });
180
+ head[name] = headCol;
181
+ }
182
+ else {
183
+ head[name] = value;
184
+ }
185
+ }
186
+ return head;
187
+ };
188
+ exports.parseHead = parseHead;
189
+ //# sourceMappingURL=upload.js.map
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@midwayjs/upload",
3
+ "version": "3.0.0-beta.9",
4
+ "description": "Midway Component for upload",
5
+ "main": "dist/index.js",
6
+ "typings": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "node --require=ts-node/register ../../node_modules/.bin/jest",
10
+ "cov": "node --require=ts-node/register ../../node_modules/.bin/jest --coverage --forceExit",
11
+ "ci": "npm run test"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "files": [
16
+ "dist/**/*.js",
17
+ "dist/**/*.d.ts"
18
+ ],
19
+ "engines": {
20
+ "node": ">=12"
21
+ },
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "fs-extra": "^8.0.1",
25
+ "raw-body": "^2.4.1"
26
+ },
27
+ "devDependencies": {
28
+ "@midwayjs/core": "^3.0.0-beta.9",
29
+ "@midwayjs/decorator": "^3.0.0-beta.9",
30
+ "@midwayjs/mock": "^3.0.0-beta.9",
31
+ "@midwayjs/faas": "^3.0.0-beta.9",
32
+ "@midwayjs/serverless-app": "^3.0.0-beta.9",
33
+ "@midwayjs/web": "^3.0.0-beta.9",
34
+ "@midwayjs/koa": "^3.0.0-beta.9",
35
+ "@midwayjs/express": "^3.0.0-beta.9"
36
+ }
37
+ }
package/readme.md ADDED
@@ -0,0 +1,82 @@
1
+ ## Upload 上传组件
2
+
3
+ 适用于 `@midwayjs/faas` 、`@midwayjs/web` 、`@midwayjs/koa` 和 `@midwayjs/express` 多种框架的通用上传组件,支持 `file` (服务器临时文件)、`stream` (流)多种模式。
4
+
5
+ ### Usage
6
+
7
+ 1. 安装依赖
8
+ ```shell
9
+ tnpm i @midwayjs/upload --save
10
+ ```
11
+ 2. 在 configuration 中引入组件,
12
+ ```ts
13
+ import * as upload from '../../../../src';
14
+ @Configuration({
15
+ imports: [
16
+ // ...other components
17
+ upload
18
+ ],
19
+ importConfigs: [
20
+ {
21
+ default: {
22
+ upload: { // 上传组件的配置
23
+ mode: upload.UploadMode.File, // 默认为 file 模式
24
+ }
25
+ }
26
+ }
27
+ ]
28
+ })
29
+ export class AutoConfiguration {}
30
+ ```
31
+
32
+ 3. 在代码中获取上传的文件
33
+ ```ts
34
+ @Controller('/')
35
+ export class HomeController {
36
+
37
+ @Inject()
38
+ ctx;
39
+
40
+ @Post('/upload')
41
+ async upload() {
42
+ const { files, fields } = this.ctx;
43
+ /*
44
+ files = [
45
+ {
46
+ filename: 'test.pdf', // 文件原名
47
+ data: '/var/tmp/xxx.pdf', // mode 为 file 时为服务器临时文件地址
48
+ fieldname: 'test1', // 表单 field 名
49
+ mimeType: 'application/pdf', // mime
50
+ },
51
+ {
52
+ filename: 'test.pdf', // 文件原名
53
+ data: ReadStream, // mode 为 stream 时为服务器临时文件地址
54
+ fieldname: 'test2', // 表单 field 名
55
+ mimeType: 'application/pdf', // mime
56
+ },
57
+ // ...file 下支持同时上传多个文件
58
+ ]
59
+
60
+ */
61
+ return {
62
+ files,
63
+ fields
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+
70
+ ### 配置
71
+ ```ts
72
+ export const upload = {
73
+ // mode: UploadMode, 默认为file,即上传到服务器临时目录,可以配置为 stream
74
+ mode: 'file',
75
+ // fileSize: string, 最大上传文件大小,默认为 10mb
76
+ fileSize: '10mb',
77
+ // whitelist: string[],文件扩展名白名单,默认为 null
78
+ whitelist: null,
79
+ // tmpdir: string,上传的文件临时存储路径
80
+ tmpdir: join(tmpdir(), 'midway-upload-files'),
81
+ }
82
+ ```