koa-simple-static
Advanced tools
Comparing version 3.0.3 to 4.0.0
450
lib/index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = void 0; | ||
var _crypto = require("crypto"); | ||
var _path = require("path"); | ||
var _fs = require("mz/fs"); | ||
var _zlib = require("mz/zlib"); | ||
var _mimeTypes = require("mime-types"); | ||
var _compressible = _interopRequireDefault(require("compressible")); | ||
var _fsReaddirRecursive = _interopRequireDefault(require("fs-readdir-recursive")); | ||
var _zeelib = require("zeelib"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const prefix = '/'; | ||
const loadFile = (name, dir, options, files) => { | ||
const pathname = (0, _path.normalize)((0, _path.join)(prefix, name)); | ||
const obj = files[pathname] = files[pathname] ? files[pathname] : {}; | ||
const filename = obj.path = (0, _path.join)(dir, name); | ||
const stats = (0, _fs.statSync)(filename); | ||
let buffer = (0, _fs.readFileSync)(filename); | ||
obj.cacheControl = options.cacheControl; | ||
obj.maxAge = obj.maxAge ? obj.maxAge : options.maxAge || 0; | ||
obj.type = obj.mime = (0, _mimeTypes.lookup)(pathname) || 'application/octet-stream'; | ||
obj.mtime = stats.mtime; | ||
obj.length = stats.size; // $FlowFixMe see https://github.com/facebook/flow/blob/v0.65.0/lib/node.js#L359 | ||
obj.md5 = (0, _crypto.createHash)('md5').update(buffer).digest('base64'); | ||
obj.buffer = buffer; | ||
buffer = null; | ||
return obj; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
const simpleStatic = options => { | ||
const dir = (0, _path.normalize)(options.dir); | ||
const files = {}; | ||
(0, _fsReaddirRecursive.default)(dir).forEach(name => { | ||
loadFile(name, dir, options, files); | ||
}); | ||
return async (ctx, next) => { | ||
// only accept HEAD and GET | ||
if (ctx.method !== 'HEAD' && ctx.method !== 'GET') { | ||
await next(); | ||
return; | ||
} // check prefix first to avoid calculate | ||
if (ctx.path.indexOf(prefix) !== 0) { | ||
await next(); | ||
return; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
if (options.extraHeaders && Array.isArray(options.extraHeaders) && options.extraHeaders.length) { | ||
options.extraHeaders.forEach(header => { | ||
for (const h in header) { | ||
// eslint-disable-line guard-for-in | ||
ctx.append(h, header[h]); | ||
} | ||
}); | ||
} // decode for `/%E4%B8%AD%E6%96%87` | ||
// normalize for `//index` | ||
let filename = (0, _zeelib.safeDecodeURIComponent)((0, _path.normalize)(ctx.path)); | ||
let file = files[filename]; // try to load file | ||
if (!file) { | ||
if ((0, _path.basename)(filename)[0] === '.') { | ||
await next(); | ||
return; | ||
} // handle index.html | ||
let hasIndex = false; | ||
try { | ||
hasIndex = await (0, _fs.statSync)((0, _path.normalize)((0, _path.join)(dir, `${filename}/index.html`))).isFile(); | ||
} catch (_) {} | ||
if (hasIndex) { | ||
filename = `${filename}/index.html`; | ||
} | ||
if (filename.charAt(0) === _path.sep) { | ||
filename = filename.slice(1); | ||
} // disallow ../ | ||
const fullPath = (0, _path.join)(dir, filename); | ||
if (fullPath.indexOf(dir) !== 0 && fullPath !== 'index.html') { | ||
await next(); | ||
return; | ||
} | ||
let s; | ||
try { | ||
s = await (0, _fs.statSync)((0, _path.join)(dir, filename)); | ||
} catch (err) { | ||
await next(); | ||
return; | ||
} | ||
if (!s.isFile()) { | ||
await next(); | ||
return; | ||
} | ||
file = loadFile(filename, dir, options, files); | ||
} | ||
ctx.status = 200; | ||
ctx.vary('Accept-Encoding'); | ||
if (!file.buffer) { | ||
const stats = await (0, _fs.statSync)(file.path); | ||
if (stats.mtime > file.mtime) { | ||
file.mtime = stats.mtime; | ||
file.md5 = null; | ||
file.length = stats.size; | ||
} | ||
} | ||
ctx.response.lastModified = file.mtime; | ||
if (file.md5) { | ||
ctx.response.etag = file.md5; | ||
} | ||
if (ctx.fresh) { | ||
ctx.status = 304; | ||
return; | ||
} | ||
ctx.type = file.type; | ||
ctx.length = file.zipBuffer ? file.zipBuffer.length : file.length; | ||
ctx.set('cache-control', `public, max-age=${file.maxAge}`); | ||
if (file.md5) { | ||
ctx.set('content-md5', file.md5); | ||
} | ||
if (ctx.method === 'HEAD') { | ||
return; | ||
} | ||
const acceptGzip = ctx.acceptsEncodings('gzip') === 'gzip'; | ||
if (file.zipBuffer) { | ||
if (acceptGzip) { | ||
ctx.set('content-encoding', 'gzip'); | ||
ctx.body = file.zipBuffer; | ||
} else { | ||
ctx.body = file.buffer; | ||
} | ||
return; | ||
} | ||
const shouldGzip = file.length > 1024 && acceptGzip && (0, _compressible.default)(file.type); | ||
if (file.buffer) { | ||
if (shouldGzip) { | ||
file.zipBuffer = await (0, _zlib.gzip)(file.buffer); | ||
ctx.set('content-encoding', 'gzip'); | ||
ctx.body = file.zipBuffer; | ||
} else { | ||
ctx.body = file.buffer; | ||
} | ||
return; | ||
} | ||
const stream = await (0, _fs.createReadStream)(file.path); // update file hash | ||
if (!file.md5) { | ||
const hash = (0, _crypto.createHash)('md5'); | ||
stream.on('data', hash.update.bind(hash)); | ||
stream.on('end', () => { | ||
file.md5 = hash.digest('base64'); | ||
}); | ||
} | ||
ctx.body = stream; // enable gzip will remove content length | ||
if (shouldGzip) { | ||
ctx.remove('content-length'); | ||
ctx.set('content-encoding', 'gzip'); | ||
ctx.body = stream.pipe((0, _zlib.createGzip)()); | ||
} | ||
}; | ||
}; | ||
var _default = simpleStatic; | ||
exports.default = _default; | ||
module.exports = exports.default; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var crypto_1 = require("crypto"); | ||
var path_1 = require("path"); | ||
var fs_1 = require("mz/fs"); | ||
var zlib_1 = require("mz/zlib"); | ||
var mime_types_1 = require("mime-types"); | ||
var compressible_1 = __importDefault(require("compressible")); | ||
var fs_readdir_recursive_1 = __importDefault(require("fs-readdir-recursive")); | ||
var zeelib_1 = require("zeelib"); | ||
var prefix = '/'; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
var loadFile = function (name, dir, options, files) { | ||
var pathname = path_1.normalize(path_1.join(prefix, name)); | ||
var obj = (files[pathname] = files[pathname] ? files[pathname] : {}); | ||
var filename = (obj.path = path_1.join(dir, name)); | ||
var stats = fs_1.statSync(filename); | ||
var buffer = fs_1.readFileSync(filename); | ||
obj.cacheControl = options.cacheControl; | ||
obj.maxAge = obj.maxAge ? obj.maxAge : options.maxAge || 0; | ||
obj.type = obj.mime = mime_types_1.lookup(pathname) || 'application/octet-stream'; | ||
obj.mtime = stats.mtime; | ||
obj.length = stats.size; | ||
obj.md5 = crypto_1.createHash('md5') | ||
.update(buffer) | ||
.digest('base64'); | ||
obj.buffer = buffer; | ||
buffer = null; | ||
return obj; | ||
}; | ||
var simpleStatic = function (options) { | ||
var dir = path_1.normalize(options.dir); | ||
var files = {}; | ||
fs_readdir_recursive_1.default(dir).forEach(function (name) { | ||
loadFile(name, dir, options, files); | ||
}); | ||
// eslint-disable-next-line max-statements | ||
return function (ctx, next) { return __awaiter(void 0, void 0, void 0, function () { | ||
var filename, file, hasIndex, _1, fullPath, s, err_1, stats, acceptGzip, shouldGzip, _a, stream, hash_1; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (!!['HEAD', 'GET'].includes(ctx.method)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, next()]; | ||
case 1: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 2: | ||
if (!!ctx.path.startsWith(prefix)) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, next()]; | ||
case 3: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 4: | ||
if (options.extraHeaders && | ||
Array.isArray(options.extraHeaders) && | ||
options.extraHeaders.length) { | ||
options.extraHeaders.forEach(function (header) { | ||
// eslint-disable-next-line fp/no-loops, guard-for-in | ||
for (var h in header) { | ||
// eslint-disable-line guard-for-in | ||
ctx.append(h, header[h]); | ||
} | ||
}); | ||
} | ||
filename = zeelib_1.safeDecodeURIComponent(path_1.normalize(ctx.path)); | ||
file = files[filename]; | ||
if (!!file) return [3 /*break*/, 20]; | ||
if (!path_1.basename(filename).startsWith('.')) return [3 /*break*/, 6]; | ||
return [4 /*yield*/, next()]; | ||
case 5: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 6: | ||
hasIndex = false; | ||
_b.label = 7; | ||
case 7: | ||
_b.trys.push([7, 9, , 10]); | ||
return [4 /*yield*/, fs_1.statSync(path_1.normalize(path_1.join(dir, filename + "/index.html"))).isFile() | ||
/* eslint-enable @typescript-eslint/await-thenable */ | ||
]; | ||
case 8: | ||
/* eslint-disable @typescript-eslint/await-thenable */ | ||
// @ts-ignore isFile is not in the types | ||
hasIndex = _b.sent(); | ||
return [3 /*break*/, 10]; | ||
case 9: | ||
_1 = _b.sent(); | ||
return [3 /*break*/, 10]; | ||
case 10: | ||
if (hasIndex) { | ||
filename = filename + "/index.html"; | ||
} | ||
if (filename.startsWith(path_1.sep)) { | ||
filename = filename.slice(1); | ||
} | ||
fullPath = path_1.join(dir, filename); | ||
if (!(!fullPath.startsWith(dir) && fullPath !== 'index.html')) return [3 /*break*/, 12]; | ||
return [4 /*yield*/, next()]; | ||
case 11: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 12: | ||
s = void 0; | ||
_b.label = 13; | ||
case 13: | ||
_b.trys.push([13, 15, , 17]); | ||
return [4 /*yield*/, fs_1.statSync(path_1.join(dir, filename))]; | ||
case 14: | ||
// eslint-disable-next-line @typescript-eslint/await-thenable | ||
s = _b.sent(); | ||
return [3 /*break*/, 17]; | ||
case 15: | ||
err_1 = _b.sent(); | ||
return [4 /*yield*/, next()]; | ||
case 16: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 17: | ||
if (!!s.isFile()) return [3 /*break*/, 19]; | ||
return [4 /*yield*/, next()]; | ||
case 18: | ||
_b.sent(); | ||
return [2 /*return*/]; | ||
case 19: | ||
file = loadFile(filename, dir, options, files); | ||
_b.label = 20; | ||
case 20: | ||
ctx.status = 200; | ||
ctx.vary('Accept-Encoding'); | ||
if (!!file.buffer) return [3 /*break*/, 22]; | ||
return [4 /*yield*/, fs_1.statSync(file.path)]; | ||
case 21: | ||
stats = _b.sent(); | ||
if (stats.mtime > file.mtime) { | ||
file.mtime = stats.mtime; | ||
file.md5 = null; | ||
file.length = stats.size; | ||
} | ||
_b.label = 22; | ||
case 22: | ||
ctx.response.lastModified = file.mtime; | ||
if (file.md5) { | ||
ctx.response.etag = file.md5; | ||
} | ||
if (ctx.fresh) { | ||
ctx.status = 304; | ||
return [2 /*return*/]; | ||
} | ||
ctx.type = file.type; | ||
ctx.length = file.zipBuffer ? file.zipBuffer.length : file.length; | ||
ctx.set('cache-control', "public, max-age=" + file.maxAge); | ||
if (file.md5) { | ||
ctx.set('content-md5', file.md5); | ||
} | ||
if (ctx.method === 'HEAD') { | ||
return [2 /*return*/]; | ||
} | ||
acceptGzip = ctx.acceptsEncodings('gzip') === 'gzip'; | ||
if (file.zipBuffer) { | ||
if (acceptGzip) { | ||
ctx.set('content-encoding', 'gzip'); | ||
ctx.body = file.zipBuffer; | ||
} | ||
else { | ||
ctx.body = file.buffer; | ||
} | ||
return [2 /*return*/]; | ||
} | ||
shouldGzip = file.length > 1024 && acceptGzip && compressible_1.default(file.type); | ||
if (!file.buffer) return [3 /*break*/, 26]; | ||
if (!shouldGzip) return [3 /*break*/, 24]; | ||
_a = file; | ||
return [4 /*yield*/, zlib_1.gzip(file.buffer)]; | ||
case 23: | ||
_a.zipBuffer = _b.sent(); | ||
ctx.set('content-encoding', 'gzip'); | ||
ctx.body = file.zipBuffer; | ||
return [3 /*break*/, 25]; | ||
case 24: | ||
ctx.body = file.buffer; | ||
_b.label = 25; | ||
case 25: return [2 /*return*/]; | ||
case 26: return [4 /*yield*/, fs_1.createReadStream(file.path) | ||
// update file hash | ||
]; | ||
case 27: | ||
stream = _b.sent(); | ||
// update file hash | ||
if (!file.md5) { | ||
hash_1 = crypto_1.createHash('md5'); | ||
stream.on('data', hash_1.update.bind(hash_1)); | ||
stream.on('end', function () { | ||
file.md5 = hash_1.digest('base64'); | ||
}); | ||
} | ||
ctx.body = stream; | ||
// enable gzip will remove content length | ||
if (shouldGzip) { | ||
ctx.remove('content-length'); | ||
ctx.set('content-encoding', 'gzip'); | ||
ctx.body = stream.pipe(zlib_1.createGzip()); | ||
} | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
}; | ||
exports.default = simpleStatic; |
{ | ||
"name": "koa-simple-static", | ||
"description": "Simple caching static file server for Koa 2.", | ||
"version": "3.0.3", | ||
"version": "4.0.0", | ||
"author": { | ||
@@ -17,14 +17,13 @@ "email": "zac@zacanger.com", | ||
"scripts": { | ||
"build": "babel src/index.js --out-file lib/index.js", | ||
"_test": "run-s -s test:lint test:ts cover", | ||
"build": "tsc", | ||
"clean": "rm -rf lib && mkdir lib", | ||
"cover": "npm run cover:flow && npm run cover:tape", | ||
"cover:flow": "flow-coverage-report --config .flow-coverage-report.json", | ||
"cover:tape": "nyc npm run test:tape", | ||
"postbuild": "flow-copy-source -i \"*.test.js\" src lib", | ||
"prebuild": "npm run test:lint && npm run cover && npm run clean && sortpack", | ||
"cover": "nyc npm run test:tape", | ||
"prebuild": "run-s -s test clean", | ||
"preversion": "npm run build", | ||
"test": "npm run test:lint && npm run test:flow && npm run test:tape", | ||
"test:flow": "flow check", | ||
"test:lint": "eslint -c .eslintrc.json src", | ||
"test:tape": "babel-tape-runner test.js | tap-spec" | ||
"test": "run-s -s test:lint test:ts test:tape", | ||
"test-server": "node test-server", | ||
"test:lint": "eslint --ext .ts -c .eslintrc.json src", | ||
"test:tape": "ts-node src/test.ts | tap-spec", | ||
"test:ts": "tsc --noEmit" | ||
}, | ||
@@ -51,38 +50,35 @@ "homepage": "https://github.com/zacanger/koa-simple-static#readme", | ||
"dependencies": { | ||
"compressible": "2.0.17", | ||
"compressible": "2.0.18", | ||
"fs-readdir-recursive": "1.1.0", | ||
"mime-types": "2.1.24", | ||
"mime-types": "2.1.26", | ||
"mz": "2.7.0", | ||
"zeelib": "8.6.0" | ||
"zeelib": "11.0.9" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "7.4.4", | ||
"@babel/core": "7.4.4", | ||
"@babel/preset-env": "7.4.4", | ||
"@babel/preset-flow": "7.0.0", | ||
"@babel/register": "7.4.4", | ||
"babel-eslint": "10.0.1", | ||
"babel-plugin-add-module-exports": "1.0.2", | ||
"babel-tape-runner": "3.0.0", | ||
"eslint": "5.16.0", | ||
"eslint-config-zacanger": "3.4.2", | ||
"eslint-plugin-babel": "5.3.0", | ||
"eslint-plugin-flowtype": "3.9.0", | ||
"eslint-plugin-import": "2.17.2", | ||
"eslint-plugin-node": "9.0.1", | ||
"eslint-plugin-promise": "4.1.1", | ||
"eslint-plugin-unicorn": "8.0.2", | ||
"flow-bin": "0.77.0", | ||
"flow-copy-source": "2.0.6", | ||
"flow-coverage-report": "0.6.1", | ||
"@types/compressible": "2.0.0", | ||
"@types/fs-readdir-recursive": "1.0.0", | ||
"@types/koa": "2.11.0", | ||
"@types/mime-types": "2.1.0", | ||
"@types/mz": "2.7.0", | ||
"@types/node": "13.1.8", | ||
"@types/supertest": "2.0.8", | ||
"@types/tape": "4.2.33", | ||
"eslint": "6.8.0", | ||
"eslint-plugin-zacanger": "1.0.0", | ||
"husky": "4.0.10", | ||
"istanbul": "0.4.5", | ||
"koa": "2.7.0", | ||
"nyc": "14.1.1", | ||
"sortpack": "1.1.6", | ||
"koa": "2.11.0", | ||
"lint-staged": "10.0.1", | ||
"npm-run-all": "4.1.5", | ||
"nyc": "15.0.0", | ||
"prettier": "1.19.1", | ||
"sortpack": "2.0.4", | ||
"supertest": "4.0.2", | ||
"tap-spec": "5.0.0", | ||
"tape": "4.10.1" | ||
"tape": "4.13.0", | ||
"ts-node": "8.6.2", | ||
"typescript": "3.7.5" | ||
}, | ||
"engines": { | ||
"node": ">=10.0.0" | ||
"node": ">=12.0.0" | ||
}, | ||
@@ -100,3 +96,3 @@ "nyc": { | ||
"require": [ | ||
"@babel/register" | ||
"ts-node/register" | ||
], | ||
@@ -109,3 +105,16 @@ "sourceMap": true | ||
"url": "https://ko-fi.com/zacanger" | ||
}, | ||
"lint-staged": { | ||
"*.ts": [ | ||
"prettier --write" | ||
], | ||
"package.json": [ | ||
"sortpack" | ||
] | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
} | ||
} |
@@ -5,3 +5,3 @@ # Koa Simple Static | ||
[![Known Vulnerabilities](https://snyk.io/test/github/zacanger/koa-simple-static/badge.svg)](https://snyk.io/test/github/zacanger/koa-simple-static) [![ko-fi](https://img.shields.io/badge/donate-KoFi-yellow.svg)](https://ko-fi.com/U7U2110VB) [![Patreon](https://img.shields.io/badge/patreon-donate-yellow.svg)](https://www.patreon.com/zacanger) [![Support with PayPal](https://img.shields.io/badge/paypal-donate-yellow.png)](https://paypal.me/zacanger) | ||
[![CircleCI](https://circleci.com/gh/zacanger/koa-simple-static.svg?style=svg)](https://circleci.com/gh/zacanger/koa-simple-static) [![codecov](https://codecov.io/gh/zacanger/koa-simple-static/branch/master/graph/badge.svg)](https://codecov.io/gh/zacanger/koa-simple-static) [![Maintainability](https://api.codeclimate.com/v1/badges/56ce56310829afe0d717/maintainability)](https://codeclimate.com/github/zacanger/koa-simple-static/maintainability) [![Known Vulnerabilities](https://snyk.io/test/github/zacanger/koa-simple-static/badge.svg)](https://snyk.io/test/github/zacanger/koa-simple-static) [![ko-fi](https://img.shields.io/badge/donate-KoFi-yellow.svg)](https://ko-fi.com/U7U2110VB) [![Patreon](https://img.shields.io/badge/patreon-donate-yellow.svg)](https://www.patreon.com/zacanger) [![Support with PayPal](https://img.shields.io/badge/paypal-donate-yellow.png)](https://paypal.me/zacanger) | ||
@@ -21,3 +21,3 @@ -------- | ||
``` | ||
npm i -S koa-simple-static | ||
npm i koa-simple-static | ||
``` | ||
@@ -35,5 +35,5 @@ | ||
* `dir: str` — directory you want to serve | ||
* `maxAge: ?number = 0` — cache control max age (in seconds) | ||
* `extraHeaders: ?Object[]` — any extra headers you wish to set for requests served by this module | ||
* `dir: string` — directory you want to serve | ||
* `maxAge?: number = 0` — cache control max age (in seconds) | ||
* `extraHeaders?: Object[]` — any extra headers you wish to set for requests served by this module | ||
* The format for this is `[ { 'Link': '</foo.js>; rel=preload; as=script' }, { 'Set-Cookie': 'foo=bar; path=/;' } ]` | ||
@@ -56,6 +56,10 @@ | ||
app.listen(port) | ||
console.log(`Serving on ${port}!`) | ||
app.listen(port, () => { | ||
console.log(`Serving on ${port}!`) | ||
}) | ||
``` | ||
**Important** if you're using `require`, you'll need to | ||
`require('koa-simple-static').default`. | ||
## FAQ | ||
@@ -68,15 +72,4 @@ | ||
* I'm getting errors but my code is fine? | ||
* If you're on Node pre-8.0.0, you'll need to use Babel in front of your server. | ||
Example: | ||
```javascript | ||
require('babel-register')({ | ||
babelrc: false, | ||
presets: [ require('babel-preset-latest-minimal') ] | ||
}) | ||
require('./server') | ||
``` | ||
* I recommend using `babel-register` in development and compiling for | ||
production. | ||
* Is this production-ready? | ||
* Yes. | ||
* How old is your version of Node? You'll need to be on the versions supported | ||
in the `engines` field, or else Babelify or otherwise compile your server. | ||
@@ -86,4 +79,4 @@ ## Contributing | ||
* Issues and PRs are welcome! Please keep in mind that this is feature complete. | ||
* This project uses Flow. It will be easiest if your editor is configured to | ||
work with `eslint` and `flow`. | ||
* This project uses TypeScript. It will be easiest if your editor is configured to | ||
work with `eslint` and `tsc`. | ||
* Please run tests! | ||
@@ -90,0 +83,0 @@ * If you're changing or adding functionality, please _add_ tests! |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40197
23
7
675
80
2
2
+ Addedcompressible@2.0.18(transitive)
+ Addedmime-db@1.43.0(transitive)
+ Addedmime-types@2.1.26(transitive)
+ Addedzeelib@11.0.9(transitive)
- Removedcompressible@2.0.17(transitive)
- Removedmime-db@1.40.0(transitive)
- Removedmime-types@2.1.24(transitive)
- Removedzeelib@8.6.0(transitive)
Updatedcompressible@2.0.18
Updatedmime-types@2.1.26
Updatedzeelib@11.0.9