├── .gitignore
├── .vscode
└── settings.json
├── index.ts
├── package.json
├── readme.md
├── tsconfig.json
├── utils.ts
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | uploads/
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "./node_modules/typescript/lib"
3 | }
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import * as express from 'express'
2 | import * as multer from 'multer'
3 | import * as cors from 'cors'
4 | import * as fs from 'fs'
5 | import * as path from 'path'
6 | import * as Loki from 'lokijs'
7 | import { imageFilter, loadCollection, cleanFolder } from './utils';
8 |
9 | // setup
10 | const DB_NAME = 'db.json';
11 | const COLLECTION_NAME = 'images';
12 | const UPLOAD_PATH = 'uploads';
13 | const upload = multer({ dest: `${UPLOAD_PATH}/`, fileFilter: imageFilter });
14 | const db = new Loki(`${UPLOAD_PATH}/${DB_NAME}`, { persistenceMethod: 'fs' });
15 |
16 | // optional: clean all data before start
17 | // cleanFolder(UPLOAD_PATH);
18 |
19 | // app
20 | const app = express();
21 | app.use(cors());
22 |
23 | app.get('/', async (req, res) => {
24 | // default route
25 | res.send(`
26 |
Demo file upload
27 | Please refer to my tutorial for details.
28 |
29 | - GET /images - list all upload images
30 | - GET /images/{id} - get one uploaded image
31 | - POST /profile - handle single image upload
32 | - POST /photos/upload - handle multiple images upload
33 |
34 | `);
35 | })
36 |
37 | app.post('/profile', upload.single('avatar'), async (req, res) => {
38 | try {
39 | const col = await loadCollection(COLLECTION_NAME, db);
40 | const data = col.insert(req.file);
41 |
42 | db.saveDatabase();
43 | res.send({ id: data.$loki, fileName: data.filename, originalName: data.originalname });
44 | } catch (err) {
45 | res.sendStatus(400);
46 | }
47 | })
48 |
49 | app.post('/photos/upload', upload.array('photos', 12), async (req, res) => {
50 | try {
51 | const col = await loadCollection(COLLECTION_NAME, db)
52 | let data = [].concat(col.insert(req.files));
53 |
54 | db.saveDatabase();
55 | res.send(data.map(x => ({ id: x.$loki, fileName: x.filename, originalName: x.originalname })));
56 | } catch (err) {
57 | res.sendStatus(400);
58 | }
59 | })
60 |
61 | app.get('/images', async (req, res) => {
62 | try {
63 | const col = await loadCollection(COLLECTION_NAME, db);
64 | res.send(col.data);
65 | } catch (err) {
66 | res.sendStatus(400);
67 | }
68 | })
69 |
70 | app.get('/images/:id', async (req, res) => {
71 | try {
72 | const col = await loadCollection(COLLECTION_NAME, db);
73 | const result = col.get(req.params.id);
74 |
75 | if (!result) {
76 | res.sendStatus(404);
77 | return;
78 | };
79 |
80 | res.setHeader('Content-Type', result.mimetype);
81 | fs.createReadStream(path.join(UPLOAD_PATH, result.filename)).pipe(res);
82 | } catch (err) {
83 | res.sendStatus(400);
84 | }
85 | })
86 |
87 | app.listen(3000, function () {
88 | console.log('listening on port 3000!');
89 | })
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "file-upload-express",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "scripts": {
7 | "prestart": "tsc",
8 | "start": "node dist/index.js"
9 | },
10 | "dependencies": {
11 | "cors": "^2.8.4",
12 | "del": "^3.0.0",
13 | "express": "^4.16.3",
14 | "lokijs": "^1.5.3",
15 | "multer": "^1.3.0"
16 | },
17 | "devDependencies": {
18 | "@types/del": "^3.0.1",
19 | "@types/express": "^4.11.1",
20 | "@types/lokijs": "^1.5.2",
21 | "@types/multer": "^1.3.6",
22 | "typescript": "^2.8.1"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # File upload with Node, Express, Mutler, Typescript
2 |
3 | This is the repo for tutorial: https://scotch.io/tutorials/express-file-uploads-with-multer.
4 |
5 | 1. Install [nodejs](https://nodejs.org/en/) (version 7.5+) and [yarn](https://yarnpkg.com/en/docs/install).
6 | 2. Go to project directory, run `yarn`.
7 | 3. Start the application, run `yarn start`.
8 | 4. Go to `localhost:3000`
9 |
10 | ## API End Points
11 |
12 | 1. Upload an image via `localhost:3000/profile`, avatar field.
13 | 2. Bulk Upload images via `localhost:3000/photos/upload`, photos field.
14 | 3. View list of images via `localhost:3000/images`.
15 | 4. Get a single image via `localhost:3000/images/{imageId}`.
16 |
17 | # License
18 | [](/LICENSE)
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "moduleResolution": "node",
5 | "target": "es6",
6 | "noImplicitAny": false,
7 | "sourceMap": true,
8 | "outDir": "dist"
9 | }
10 | }
--------------------------------------------------------------------------------
/utils.ts:
--------------------------------------------------------------------------------
1 | import * as del from 'del';
2 | import { Collection } from 'lokijs';
3 |
4 | const imageFilter = function (req, file, cb) {
5 | // accept image only
6 | if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
7 | return cb(new Error('Only image files are allowed!'), false);
8 | }
9 | cb(null, true);
10 | };
11 |
12 | const loadCollection = function (colName, db: Loki): Promise> {
13 | return new Promise(resolve => {
14 | db.loadDatabase({}, () => {
15 | const _collection = db.getCollection(colName) || db.addCollection(colName);
16 | resolve(_collection);
17 | })
18 | });
19 | }
20 |
21 | const cleanFolder = function (folderPath) {
22 | // delete files inside folder but not the folder itself
23 | del.sync([`${folderPath}/**`, `!${folderPath}`]);
24 | };
25 |
26 | export { imageFilter, loadCollection, cleanFolder }
27 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@types/body-parser@*":
6 | version "1.16.8"
7 | resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.16.8.tgz#687ec34140624a3bec2b1a8ea9268478ae8f3be3"
8 | dependencies:
9 | "@types/express" "*"
10 | "@types/node" "*"
11 |
12 | "@types/del@^3.0.1":
13 | version "3.0.1"
14 | resolved "https://registry.yarnpkg.com/@types/del/-/del-3.0.1.tgz#4712da8c119873cbbf533ad8dbf1baac5940ac5d"
15 | dependencies:
16 | "@types/glob" "*"
17 |
18 | "@types/express-serve-static-core@*":
19 | version "4.0.40"
20 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.0.40.tgz#168e82978bffc81ee7737bc60728d64733a4f37b"
21 | dependencies:
22 | "@types/node" "*"
23 |
24 | "@types/express@*":
25 | version "4.0.35"
26 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.0.35.tgz#6267c7b60a51fac473467b3c4a02cd1e441805fe"
27 | dependencies:
28 | "@types/express-serve-static-core" "*"
29 | "@types/serve-static" "*"
30 |
31 | "@types/express@^4.11.1":
32 | version "4.11.1"
33 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.11.1.tgz#f99663b3ab32d04cb11db612ef5dd7933f75465b"
34 | dependencies:
35 | "@types/body-parser" "*"
36 | "@types/express-serve-static-core" "*"
37 | "@types/serve-static" "*"
38 |
39 | "@types/glob@*":
40 | version "5.0.30"
41 | resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.30.tgz#1026409c5625a8689074602808d082b2867b8a51"
42 | dependencies:
43 | "@types/minimatch" "*"
44 | "@types/node" "*"
45 |
46 | "@types/lokijs@^1.5.2":
47 | version "1.5.2"
48 | resolved "https://registry.yarnpkg.com/@types/lokijs/-/lokijs-1.5.2.tgz#ed228f080033ce1fb16eff4acde65cb9ae0f1bf2"
49 |
50 | "@types/mime@*":
51 | version "0.0.29"
52 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-0.0.29.tgz#fbcfd330573b912ef59eeee14602bface630754b"
53 |
54 | "@types/minimatch@*":
55 | version "2.0.29"
56 | resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a"
57 |
58 | "@types/multer@^1.3.6":
59 | version "1.3.6"
60 | resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.3.6.tgz#e00454074bf9fd86d20ea652eba9850eb76604c4"
61 | dependencies:
62 | "@types/express" "*"
63 |
64 | "@types/node@*":
65 | version "7.0.5"
66 | resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.5.tgz#96a0f0a618b7b606f1ec547403c00650210bfbb7"
67 |
68 | "@types/serve-static@*":
69 | version "1.7.31"
70 | resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.7.31.tgz#15456de8d98d6b4cff31be6c6af7492ae63f521a"
71 | dependencies:
72 | "@types/express-serve-static-core" "*"
73 | "@types/mime" "*"
74 |
75 | accepts@~1.3.5:
76 | version "1.3.5"
77 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
78 | dependencies:
79 | mime-types "~2.1.18"
80 | negotiator "0.6.1"
81 |
82 | append-field@^0.1.0:
83 | version "0.1.0"
84 | resolved "https://registry.yarnpkg.com/append-field/-/append-field-0.1.0.tgz#6ddc58fa083c7bc545d3c5995b2830cc2366d44a"
85 |
86 | array-flatten@1.1.1:
87 | version "1.1.1"
88 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
89 |
90 | array-union@^1.0.1:
91 | version "1.0.2"
92 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
93 | dependencies:
94 | array-uniq "^1.0.1"
95 |
96 | array-uniq@^1.0.1:
97 | version "1.0.3"
98 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
99 |
100 | balanced-match@^0.4.1:
101 | version "0.4.2"
102 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
103 |
104 | body-parser@1.18.2:
105 | version "1.18.2"
106 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454"
107 | dependencies:
108 | bytes "3.0.0"
109 | content-type "~1.0.4"
110 | debug "2.6.9"
111 | depd "~1.1.1"
112 | http-errors "~1.6.2"
113 | iconv-lite "0.4.19"
114 | on-finished "~2.3.0"
115 | qs "6.5.1"
116 | raw-body "2.3.2"
117 | type-is "~1.6.15"
118 |
119 | brace-expansion@^1.0.0:
120 | version "1.1.6"
121 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
122 | dependencies:
123 | balanced-match "^0.4.1"
124 | concat-map "0.0.1"
125 |
126 | buffer-shims@^1.0.0:
127 | version "1.0.0"
128 | resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
129 |
130 | busboy@^0.2.11:
131 | version "0.2.14"
132 | resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
133 | dependencies:
134 | dicer "0.2.5"
135 | readable-stream "1.1.x"
136 |
137 | bytes@3.0.0:
138 | version "3.0.0"
139 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
140 |
141 | concat-map@0.0.1:
142 | version "0.0.1"
143 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
144 |
145 | concat-stream@^1.5.0:
146 | version "1.6.0"
147 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
148 | dependencies:
149 | inherits "^2.0.3"
150 | readable-stream "^2.2.2"
151 | typedarray "^0.0.6"
152 |
153 | content-disposition@0.5.2:
154 | version "0.5.2"
155 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
156 |
157 | content-type@~1.0.4:
158 | version "1.0.4"
159 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
160 |
161 | cookie-signature@1.0.6:
162 | version "1.0.6"
163 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
164 |
165 | cookie@0.3.1:
166 | version "0.3.1"
167 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
168 |
169 | core-util-is@~1.0.0:
170 | version "1.0.2"
171 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
172 |
173 | cors@^2.8.4:
174 | version "2.8.4"
175 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686"
176 | dependencies:
177 | object-assign "^4"
178 | vary "^1"
179 |
180 | debug@2.6.9:
181 | version "2.6.9"
182 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
183 | dependencies:
184 | ms "2.0.0"
185 |
186 | del@^3.0.0:
187 | version "3.0.0"
188 | resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
189 | dependencies:
190 | globby "^6.1.0"
191 | is-path-cwd "^1.0.0"
192 | is-path-in-cwd "^1.0.0"
193 | p-map "^1.1.1"
194 | pify "^3.0.0"
195 | rimraf "^2.2.8"
196 |
197 | depd@1.1.1:
198 | version "1.1.1"
199 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
200 |
201 | depd@~1.1.1, depd@~1.1.2:
202 | version "1.1.2"
203 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
204 |
205 | destroy@~1.0.4:
206 | version "1.0.4"
207 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
208 |
209 | dicer@0.2.5:
210 | version "0.2.5"
211 | resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
212 | dependencies:
213 | readable-stream "1.1.x"
214 | streamsearch "0.1.2"
215 |
216 | ee-first@1.1.1:
217 | version "1.1.1"
218 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
219 |
220 | encodeurl@~1.0.2:
221 | version "1.0.2"
222 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
223 |
224 | escape-html@~1.0.3:
225 | version "1.0.3"
226 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
227 |
228 | etag@~1.8.1:
229 | version "1.8.1"
230 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
231 |
232 | express@^4.16.3:
233 | version "4.16.3"
234 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
235 | dependencies:
236 | accepts "~1.3.5"
237 | array-flatten "1.1.1"
238 | body-parser "1.18.2"
239 | content-disposition "0.5.2"
240 | content-type "~1.0.4"
241 | cookie "0.3.1"
242 | cookie-signature "1.0.6"
243 | debug "2.6.9"
244 | depd "~1.1.2"
245 | encodeurl "~1.0.2"
246 | escape-html "~1.0.3"
247 | etag "~1.8.1"
248 | finalhandler "1.1.1"
249 | fresh "0.5.2"
250 | merge-descriptors "1.0.1"
251 | methods "~1.1.2"
252 | on-finished "~2.3.0"
253 | parseurl "~1.3.2"
254 | path-to-regexp "0.1.7"
255 | proxy-addr "~2.0.3"
256 | qs "6.5.1"
257 | range-parser "~1.2.0"
258 | safe-buffer "5.1.1"
259 | send "0.16.2"
260 | serve-static "1.13.2"
261 | setprototypeof "1.1.0"
262 | statuses "~1.4.0"
263 | type-is "~1.6.16"
264 | utils-merge "1.0.1"
265 | vary "~1.1.2"
266 |
267 | finalhandler@1.1.1:
268 | version "1.1.1"
269 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
270 | dependencies:
271 | debug "2.6.9"
272 | encodeurl "~1.0.2"
273 | escape-html "~1.0.3"
274 | on-finished "~2.3.0"
275 | parseurl "~1.3.2"
276 | statuses "~1.4.0"
277 | unpipe "~1.0.0"
278 |
279 | forwarded@~0.1.2:
280 | version "0.1.2"
281 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
282 |
283 | fresh@0.5.2:
284 | version "0.5.2"
285 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
286 |
287 | fs.realpath@^1.0.0:
288 | version "1.0.0"
289 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
290 |
291 | glob@^7.0.3, glob@^7.0.5:
292 | version "7.1.1"
293 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
294 | dependencies:
295 | fs.realpath "^1.0.0"
296 | inflight "^1.0.4"
297 | inherits "2"
298 | minimatch "^3.0.2"
299 | once "^1.3.0"
300 | path-is-absolute "^1.0.0"
301 |
302 | globby@^6.1.0:
303 | version "6.1.0"
304 | resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
305 | dependencies:
306 | array-union "^1.0.1"
307 | glob "^7.0.3"
308 | object-assign "^4.0.1"
309 | pify "^2.0.0"
310 | pinkie-promise "^2.0.0"
311 |
312 | http-errors@1.6.2:
313 | version "1.6.2"
314 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736"
315 | dependencies:
316 | depd "1.1.1"
317 | inherits "2.0.3"
318 | setprototypeof "1.0.3"
319 | statuses ">= 1.3.1 < 2"
320 |
321 | http-errors@~1.6.2:
322 | version "1.6.3"
323 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
324 | dependencies:
325 | depd "~1.1.2"
326 | inherits "2.0.3"
327 | setprototypeof "1.1.0"
328 | statuses ">= 1.4.0 < 2"
329 |
330 | iconv-lite@0.4.19:
331 | version "0.4.19"
332 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
333 |
334 | inflight@^1.0.4:
335 | version "1.0.6"
336 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
337 | dependencies:
338 | once "^1.3.0"
339 | wrappy "1"
340 |
341 | inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.1:
342 | version "2.0.3"
343 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
344 |
345 | ipaddr.js@1.6.0:
346 | version "1.6.0"
347 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b"
348 |
349 | is-path-cwd@^1.0.0:
350 | version "1.0.0"
351 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
352 |
353 | is-path-in-cwd@^1.0.0:
354 | version "1.0.0"
355 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
356 | dependencies:
357 | is-path-inside "^1.0.0"
358 |
359 | is-path-inside@^1.0.0:
360 | version "1.0.0"
361 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
362 | dependencies:
363 | path-is-inside "^1.0.1"
364 |
365 | isarray@0.0.1:
366 | version "0.0.1"
367 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
368 |
369 | isarray@~1.0.0:
370 | version "1.0.0"
371 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
372 |
373 | lokijs@^1.5.3:
374 | version "1.5.3"
375 | resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.3.tgz#6952722ffa3049a55a5e1c10ee4a0947a3e5e19b"
376 |
377 | media-typer@0.3.0:
378 | version "0.3.0"
379 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
380 |
381 | merge-descriptors@1.0.1:
382 | version "1.0.1"
383 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
384 |
385 | methods@~1.1.2:
386 | version "1.1.2"
387 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
388 |
389 | mime-db@~1.26.0:
390 | version "1.26.0"
391 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff"
392 |
393 | mime-db@~1.33.0:
394 | version "1.33.0"
395 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
396 |
397 | mime-types@~2.1.13:
398 | version "2.1.14"
399 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee"
400 | dependencies:
401 | mime-db "~1.26.0"
402 |
403 | mime-types@~2.1.18:
404 | version "2.1.18"
405 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
406 | dependencies:
407 | mime-db "~1.33.0"
408 |
409 | mime@1.4.1:
410 | version "1.4.1"
411 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
412 |
413 | minimatch@^3.0.2:
414 | version "3.0.3"
415 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
416 | dependencies:
417 | brace-expansion "^1.0.0"
418 |
419 | minimist@0.0.8:
420 | version "0.0.8"
421 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
422 |
423 | mkdirp@^0.5.1:
424 | version "0.5.1"
425 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
426 | dependencies:
427 | minimist "0.0.8"
428 |
429 | ms@2.0.0:
430 | version "2.0.0"
431 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
432 |
433 | multer@^1.3.0:
434 | version "1.3.0"
435 | resolved "https://registry.yarnpkg.com/multer/-/multer-1.3.0.tgz#092b2670f6846fa4914965efc8cf94c20fec6cd2"
436 | dependencies:
437 | append-field "^0.1.0"
438 | busboy "^0.2.11"
439 | concat-stream "^1.5.0"
440 | mkdirp "^0.5.1"
441 | object-assign "^3.0.0"
442 | on-finished "^2.3.0"
443 | type-is "^1.6.4"
444 | xtend "^4.0.0"
445 |
446 | negotiator@0.6.1:
447 | version "0.6.1"
448 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
449 |
450 | object-assign@^3.0.0:
451 | version "3.0.0"
452 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
453 |
454 | object-assign@^4, object-assign@^4.0.1:
455 | version "4.1.1"
456 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
457 |
458 | on-finished@^2.3.0, on-finished@~2.3.0:
459 | version "2.3.0"
460 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
461 | dependencies:
462 | ee-first "1.1.1"
463 |
464 | once@^1.3.0:
465 | version "1.4.0"
466 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
467 | dependencies:
468 | wrappy "1"
469 |
470 | p-map@^1.1.1:
471 | version "1.2.0"
472 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
473 |
474 | parseurl@~1.3.2:
475 | version "1.3.2"
476 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
477 |
478 | path-is-absolute@^1.0.0:
479 | version "1.0.1"
480 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
481 |
482 | path-is-inside@^1.0.1:
483 | version "1.0.2"
484 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
485 |
486 | path-to-regexp@0.1.7:
487 | version "0.1.7"
488 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
489 |
490 | pify@^2.0.0:
491 | version "2.3.0"
492 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
493 |
494 | pify@^3.0.0:
495 | version "3.0.0"
496 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
497 |
498 | pinkie-promise@^2.0.0:
499 | version "2.0.1"
500 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
501 | dependencies:
502 | pinkie "^2.0.0"
503 |
504 | pinkie@^2.0.0:
505 | version "2.0.4"
506 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
507 |
508 | process-nextick-args@~1.0.6:
509 | version "1.0.7"
510 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
511 |
512 | proxy-addr@~2.0.3:
513 | version "2.0.3"
514 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
515 | dependencies:
516 | forwarded "~0.1.2"
517 | ipaddr.js "1.6.0"
518 |
519 | qs@6.5.1:
520 | version "6.5.1"
521 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
522 |
523 | range-parser@~1.2.0:
524 | version "1.2.0"
525 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
526 |
527 | raw-body@2.3.2:
528 | version "2.3.2"
529 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89"
530 | dependencies:
531 | bytes "3.0.0"
532 | http-errors "1.6.2"
533 | iconv-lite "0.4.19"
534 | unpipe "1.0.0"
535 |
536 | readable-stream@1.1.x:
537 | version "1.1.14"
538 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
539 | dependencies:
540 | core-util-is "~1.0.0"
541 | inherits "~2.0.1"
542 | isarray "0.0.1"
543 | string_decoder "~0.10.x"
544 |
545 | readable-stream@^2.2.2:
546 | version "2.2.2"
547 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
548 | dependencies:
549 | buffer-shims "^1.0.0"
550 | core-util-is "~1.0.0"
551 | inherits "~2.0.1"
552 | isarray "~1.0.0"
553 | process-nextick-args "~1.0.6"
554 | string_decoder "~0.10.x"
555 | util-deprecate "~1.0.1"
556 |
557 | rimraf@^2.2.8:
558 | version "2.5.4"
559 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
560 | dependencies:
561 | glob "^7.0.5"
562 |
563 | safe-buffer@5.1.1:
564 | version "5.1.1"
565 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
566 |
567 | send@0.16.2:
568 | version "0.16.2"
569 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
570 | dependencies:
571 | debug "2.6.9"
572 | depd "~1.1.2"
573 | destroy "~1.0.4"
574 | encodeurl "~1.0.2"
575 | escape-html "~1.0.3"
576 | etag "~1.8.1"
577 | fresh "0.5.2"
578 | http-errors "~1.6.2"
579 | mime "1.4.1"
580 | ms "2.0.0"
581 | on-finished "~2.3.0"
582 | range-parser "~1.2.0"
583 | statuses "~1.4.0"
584 |
585 | serve-static@1.13.2:
586 | version "1.13.2"
587 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
588 | dependencies:
589 | encodeurl "~1.0.2"
590 | escape-html "~1.0.3"
591 | parseurl "~1.3.2"
592 | send "0.16.2"
593 |
594 | setprototypeof@1.0.3:
595 | version "1.0.3"
596 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
597 |
598 | setprototypeof@1.1.0:
599 | version "1.1.0"
600 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
601 |
602 | "statuses@>= 1.3.1 < 2":
603 | version "1.3.1"
604 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
605 |
606 | "statuses@>= 1.4.0 < 2":
607 | version "1.5.0"
608 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
609 |
610 | statuses@~1.4.0:
611 | version "1.4.0"
612 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
613 |
614 | streamsearch@0.1.2:
615 | version "0.1.2"
616 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
617 |
618 | string_decoder@~0.10.x:
619 | version "0.10.31"
620 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
621 |
622 | type-is@^1.6.4:
623 | version "1.6.14"
624 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2"
625 | dependencies:
626 | media-typer "0.3.0"
627 | mime-types "~2.1.13"
628 |
629 | type-is@~1.6.15, type-is@~1.6.16:
630 | version "1.6.16"
631 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
632 | dependencies:
633 | media-typer "0.3.0"
634 | mime-types "~2.1.18"
635 |
636 | typedarray@^0.0.6:
637 | version "0.0.6"
638 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
639 |
640 | typescript@^2.8.1:
641 | version "2.8.1"
642 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624"
643 |
644 | unpipe@1.0.0, unpipe@~1.0.0:
645 | version "1.0.0"
646 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
647 |
648 | util-deprecate@~1.0.1:
649 | version "1.0.2"
650 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
651 |
652 | utils-merge@1.0.1:
653 | version "1.0.1"
654 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
655 |
656 | vary@^1:
657 | version "1.1.0"
658 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140"
659 |
660 | vary@~1.1.2:
661 | version "1.1.2"
662 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
663 |
664 | wrappy@1:
665 | version "1.0.2"
666 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
667 |
668 | xtend@^4.0.0:
669 | version "4.0.1"
670 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
671 |
--------------------------------------------------------------------------------