winston-middleware 0.2.4 → 1.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/.travis.yml CHANGED
@@ -2,4 +2,11 @@ language: node_js
2
2
  node_js:
3
3
  - "0.6"
4
4
  - "0.8"
5
- script: "npm test"
5
+ - "0.10"
6
+ - "0.11"
7
+ - "0.12"
8
+ - "iojs"
9
+
10
+ script:
11
+ - "test $TRAVIS_NODE_VERSION = '0.6' || npm test"
12
+ - "test $TRAVIS_NODE_VERSION != '0.6' || npm run-script test-coverage"
package/AUTHORS CHANGED
@@ -1,4 +1,7 @@
1
1
  Heapsource <npm@heapsource.com> (http://www.heapsource.com)
2
2
  Lars Jacob (http://jaclar.net)
3
- Jonathan Lomas (http://feedbackular.com)
3
+ Jonathan Lomas (http://floatinglomas.ca)
4
4
  Xavier Damman (http://xdamman.com)
5
+ Quentin Rossetti <quentin.rossetti@gmail.com>
6
+ Damian Kaczmarek <rush@rushbase.net>
7
+ Robbie Trencheny <me@robbiet.us> (http://robbie.io)
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2013 Heapsource.com - http://www.heapsource.com
1
+ Copyright (c) 2012-2014 Bithavoc.io - http://bithavoc.io
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
package/Readme.md CHANGED
@@ -1,12 +1,18 @@
1
1
  # winston-middleware
2
- [![Build Status](https://secure.travis-ci.org/firebaseco/winston-middleware.png)](http://travis-ci.org/firebaseco/winston-middleware)
2
+ [![Build Status](https://secure.travis-ci.org/bithavoc/winston-middleware.png)](http://travis-ci.org/bithavoc/winston-middleware)
3
3
 
4
4
  > [winston](https://github.com/flatiron/winston) middleware for express.js
5
5
 
6
6
  ## Installation
7
7
 
8
+ Newcomers should start with the latest branch which makes use of winston 1.x.x:
9
+
8
10
  npm install winston-middleware
9
11
 
12
+ If you're already using winston-middleware, and want to stick with the stable version based on winston 0.9.x, you should instead do:
13
+
14
+ npm install winston-middleware@0.3.x --save
15
+
10
16
  ## Usage
11
17
 
12
18
  winston-middleware provides middlewares for request and error logging of your express.js application. It uses 'whitelists' to select properties from the request and (new in 0.2.x) response objects.
@@ -38,7 +44,9 @@ var winston = require('winston'),
38
44
  Use `expressWinston.errorLogger(options)` to create a middleware that log the errors of the pipeline.
39
45
 
40
46
  ``` js
41
- app.use(app.router); // notice how the router goes first.
47
+ var router = require('./my-express-router');
48
+
49
+ app.use(router); // notice how the router goes first.
42
50
  app.use(expressWinston.errorLogger({
43
51
  transports: [
44
52
  new winston.transports.Console({
@@ -55,14 +63,22 @@ The logger needs to be added AFTER the express router(`app.router)`) and BEFORE
55
63
 
56
64
  ``` js
57
65
  transports: [<WinstonTransport>], // list of all winston transports instances to use.
58
- level: String // log level to use, the default is "info".
66
+ winstonInstance: <WinstonLogger>, // a winston logger instance. If this is provided the transports option is ignored
67
+ level: String, // log level to use, the default is "info".
68
+ statusLevels: Boolean // different HTTP status codes caused log messages to be logged at different levels (info/warn/error), the default is false
69
+ skip: function(req, res) // function to determine if logging is skipped, defaults to false
59
70
  ```
60
71
 
72
+ To use winston's existing transports, set `transports` to the values (as in key-value) of the `winston.default.transports` object. This may be done, for example, by using underscorejs: `transports: _.values(winston.default.transports)`.
73
+
74
+ Alternatively, if you're using a winston logger instance elsewhere and have already set up levels and transports, pass the instance into expressWinston with the `winstonInstance` option. The `transports` option is then ignored.
75
+
61
76
  ### Request Logging
62
77
 
63
78
  Use `expressWinston.logger(options)` to create a middleware to log your HTTP requests.
64
79
 
65
80
  ``` js
81
+ var router = require('./my-express-router');
66
82
 
67
83
  app.use(expressWinston.logger({
68
84
  transports: [
@@ -72,9 +88,13 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
72
88
  })
73
89
  ],
74
90
  meta: true, // optional: control whether you want to log the meta data about the request (default to true)
75
- msg: "HTTP {{req.method}} {{req.url}}" // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}"
91
+ msg: "HTTP {{req.method}} {{req.url}}", // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}"
92
+ expressFormat: true, // Use the default Express/morgan request formatting, with the same colors. Enabling this will override any msg and colorStatus if true. Will only output colors on transports with colorize set to true
93
+ colorStatus: true, // Color the status code, using the Express/morgan color palette (default green, 3XX cyan, 4XX yellow, 5XX red). Will not be recognized if expressFormat is true
94
+ ignoreRoute: function (req, res) { return false; } // optional: allows to skip some log messages based on request and/or response
76
95
  }));
77
- app.use(app.router); // notice how the router goes after the logger.
96
+
97
+ app.use(router); // notice how the router goes after the logger.
78
98
  ```
79
99
 
80
100
  ## Examples
@@ -88,6 +108,18 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
88
108
  app.use(express.bodyParser());
89
109
  app.use(express.methodOverride());
90
110
 
111
+ // Let's make our express `Router` first.
112
+ var router = express.Router();
113
+ router.get('/error', function(req, res, next) {
114
+ // here we cause an error in the pipeline so we see winston-middleware in action.
115
+ return next(new Error("This is an error and it should be logged to the console"));
116
+ });
117
+
118
+ app.get('/', function(req, res, next) {
119
+ res.write('This is a normal request, it should be logged to the console too');
120
+ res.end();
121
+ });
122
+
91
123
  // winston-middleware logger makes sense BEFORE the router.
92
124
  app.use(expressWinston.logger({
93
125
  transports: [
@@ -98,7 +130,8 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
98
130
  ]
99
131
  }));
100
132
 
101
- app.use(app.router);
133
+ // Now we can tell the app to use our routing code:
134
+ app.use(router);
102
135
 
103
136
  // winston-middleware errorLogger makes sense AFTER the router.
104
137
  app.use(expressWinston.errorLogger({
@@ -116,18 +149,8 @@ Use `expressWinston.logger(options)` to create a middleware to log your HTTP req
116
149
  showStack: true
117
150
  }));
118
151
 
119
- app.get('/error', function(req, res, next) {
120
- // here we cause an error in the pipeline so we see winston-middleware in action.
121
- return next(new Error("This is an error and it should be logged to the console"));
122
- });
123
-
124
- app.get('/', function(req, res, next) {
125
- res.write('This is a normal request, it should be logged to the console too');
126
- res.end();
127
- });
128
-
129
152
  app.listen(3000, function(){
130
- console.log("winston-middleware demo listening on port %d in %s mode", app.address().port, app.settings.env);
153
+ console.log("winston-middleware demo listening on port %d in %s mode", this.address().port, app.settings.env);
131
154
  });
132
155
  ```
133
156
 
@@ -234,11 +257,42 @@ Browse `/error` will show you how winston-middleware handles and logs the errors
234
257
  "message": "middlewareError"
235
258
  }
236
259
 
237
- ## Whitelists
260
+ ## Global Whitelists and Blacklists
261
+
262
+ winston-middleware exposes three whitelists that control which properties of the `request`, `body`, and `response` are logged:
263
+
264
+ * `requestWhitelist`
265
+ * `bodyWhitelist`, `bodyBlacklist`
266
+ * `responseWhitelist`
267
+
268
+ For example, `requestWhitelist` defaults to:
269
+
270
+ ['url', 'headers', 'method', 'httpVersion', 'originalUrl', 'query'];
271
+
272
+ Only those properties of the request object will be logged. Set or modify the whitelist as necessary.
273
+
274
+ For example, to include the session property (the session data), add the following during logger setup:
275
+
276
+ expressWinston.requestWhitelist.push('session');
277
+
278
+ The blacklisting excludes certain properties and keeps all others. If both `bodyWhitelist` and `bodyBlacklist` are set
279
+ the properties excluded by the blacklist are not included even if they are listed in the whitelist!
280
+
281
+ Example:
282
+
283
+ expressWinston.bodyBlacklist.push('secretid', 'secretproperty');
284
+
285
+ Note that you can log the whole request and/or response body:
286
+
287
+ expressWinston.requestWhitelist.push('body');
288
+ expressWinston.responseWhitelist.push('body');
289
+
290
+ ## Route-Specific Whitelists and Blacklists
291
+
238
292
  New in version 0.2.x is the ability to add whitelist elements in a route. winston-middleware adds a `_routeWhitelists` object to the `req`uest, containing `.body`, `.req` and .res` properties, to which you can set an array of 'whitelist' parameters to include in the log, specific to the route in question:
239
293
 
240
294
  ``` js
241
- app.post('/user/register', function(req, res, next) {
295
+ router.post('/user/register', function(req, res, next) {
242
296
  req._routeWhitelists.body = ['username', 'email', 'age']; // But not 'password' or 'confirm-password' or 'top-secret'
243
297
  req._routeWhitelists.res = ['_headers'];
244
298
  });
@@ -277,21 +331,42 @@ Post to `/user/register` would give you something like the following:
277
331
  "message": "HTTP GET /favicon.ico"
278
332
  }
279
333
 
334
+ Blacklisting supports only the `body` property.
335
+
336
+
337
+ ``` js
338
+ router.post('/user/register', function(req, res, next) {
339
+ req._routeWhitelists.body = ['username', 'email', 'age']; // But not 'password' or 'confirm-password' or 'top-secret'
340
+ req._routeBlacklists.body = ['username', 'password', 'confirm-password', 'top-secret'];
341
+ req._routeWhitelists.res = ['_headers'];
342
+ });
343
+ ```
344
+
345
+ If both `req._bodyWhitelist.body` and `req._bodyBlacklist.body` are set the result will be the white listed properties
346
+ excluding any black listed ones. In the above example, only 'email' and 'age' would be included.
347
+
348
+
280
349
  ## Tests
281
350
 
351
+ Run the basic Mocha tests:
352
+
282
353
  npm test
283
354
 
284
- ## Issues and Collaboration
355
+ Run the Travis-CI tests (which will fail with < 100% coverage):
285
356
 
286
- * Implement a chain of requestFilters. Currently only one requestFilter is allowed in the options.
357
+ npm test-travis
287
358
 
288
- We are accepting pull-request for these features.
359
+ Generate the `coverage.html` coverage report:
360
+
361
+ npm test-coverage
362
+
363
+ ## Issues and Collaboration
289
364
 
290
- If you ran into any problems, please use the project [Issues section](https://github.com/firebaseco/winston-middleware/issues) to search or post any bug.
365
+ If you ran into any problems, please use the project [Issues section](https://github.com/bithavoc/winston-middleware/issues) to search or post any bug.
291
366
 
292
367
  ## Contributors
293
368
 
294
- * [Johan Hernandez](https://github.com/thepumpkin1979) (https://github.com/thepumpkin1979)
369
+ * [Johan Hernandez](https://github.com/bithavoc) (https://github.com/bithavoc)
295
370
  * [Lars Jacob](https://github.com/jaclar) (https://github.com/jaclar)
296
371
  * [Jonathan Lomas](https://github.com/floatingLomas) (https://github.com/floatingLomas)
297
372
 
@@ -299,7 +374,7 @@ Also see AUTHORS file, add yourself if you are missing.
299
374
 
300
375
  ## MIT License
301
376
 
302
- Copyright (c) 2012-2014 Heapsource.com and Contributors - http://www.heapsource.com
377
+ Copyright (c) 2012-2014 Bithavoc.io and Contributors - http://bithavoc.io
303
378
 
304
379
  Permission is hereby granted, free of charge, to any person obtaining a copy
305
380
  of this software and associated documentation files (the "Software"), to deal
package/index.js CHANGED
@@ -20,6 +20,7 @@
20
20
  //
21
21
  var winston = require('winston');
22
22
  var util = require('util');
23
+ var chalk = require('chalk');
23
24
 
24
25
  //Allow this file to get an exclusive copy of underscore so it can change the template settings without affecting others
25
26
  delete require.cache[require.resolve('underscore')];
@@ -42,6 +43,12 @@ var requestWhitelist = ['url', 'headers', 'method', 'httpVersion', 'originalUrl'
42
43
  */
43
44
  var bodyWhitelist = [];
44
45
 
46
+ /**
47
+ * A default list of properties in the request body that are not allowed to be logged.
48
+ * @type {Array}
49
+ */
50
+ var bodyBlacklist = [];
51
+
45
52
  /**
46
53
  * A default list of properties in the response object that are allowed to be logged.
47
54
  * These properties will be safely included in the meta of the log.
@@ -49,6 +56,13 @@ var bodyWhitelist = [];
49
56
  */
50
57
  var responseWhitelist = ['statusCode'];
51
58
 
59
+ /**
60
+ * A list of request routes that will be skipped instead of being logged. This would be useful if routes for health checks or pings would otherwise pollute
61
+ * your log files.
62
+ * @type {Array}
63
+ */
64
+ var ignoredRoutes = [];
65
+
52
66
  /**
53
67
  * A default function to filter the properties of the req object.
54
68
  * @param req
@@ -65,23 +79,33 @@ var defaultRequestFilter = function (req, propName) {
65
79
  * @param propName
66
80
  * @return {*}
67
81
  */
68
- var defaultResponseFilter = function (req, propName) {
69
- return req[propName];
82
+ var defaultResponseFilter = function (res, propName) {
83
+ return res[propName];
84
+ };
85
+
86
+ /**
87
+ * A default function to decide whether skip logging of particular request. Doesn't skip anything (i.e. log all requests).
88
+ * @return always false
89
+ */
90
+ var defaultSkip = function() {
91
+ return false;
70
92
  };
71
93
 
72
94
  function filterObject(originalObj, whiteList, initialFilter) {
73
95
 
74
96
  var obj = {};
97
+ var fieldsSet = false;
75
98
 
76
99
  [].concat(whiteList).forEach(function (propName) {
77
100
  var value = initialFilter(originalObj, propName);
78
101
 
79
102
  if(typeof (value) !== 'undefined') {
80
103
  obj[propName] = value;
104
+ fieldsSet = true;
81
105
  };
82
106
  });
83
107
 
84
- return obj;
108
+ return fieldsSet?obj:undefined;
85
109
  }
86
110
 
87
111
  //
@@ -95,6 +119,7 @@ function errorLogger(options) {
95
119
  ensureValidOptions(options);
96
120
 
97
121
  options.requestFilter = options.requestFilter || defaultRequestFilter;
122
+ options.winstonInstance = options.winstonInstance || (new winston.Logger ({ transports: options.transports }));
98
123
 
99
124
  return function (err, req, res, next) {
100
125
 
@@ -103,12 +128,7 @@ function errorLogger(options) {
103
128
  exceptionMeta.req = filterObject(req, requestWhitelist, options.requestFilter);
104
129
 
105
130
  // This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
106
- for(var i = 0; i < options.transports.length; i++) {
107
- var transport = options.transports[i];
108
- transport.logException('middlewareError', exceptionMeta, function () {
109
- // Nothing to do here
110
- });
111
- }
131
+ options.winstonInstance.log('error', 'middlewareError', exceptionMeta);
112
132
 
113
133
  next(err);
114
134
  };
@@ -123,13 +143,28 @@ function errorLogger(options) {
123
143
  function logger(options) {
124
144
 
125
145
  ensureValidOptions(options);
146
+ ensureValidLoggerOptions(options);
126
147
 
127
148
  options.requestFilter = options.requestFilter || defaultRequestFilter;
128
149
  options.responseFilter = options.responseFilter || defaultResponseFilter;
150
+ options.winstonInstance = options.winstonInstance || (new winston.Logger ({ transports: options.transports }));
129
151
  options.level = options.level || "info";
152
+ options.statusLevels = options.statusLevels || false;
130
153
  options.msg = options.msg || "HTTP {{req.method}} {{req.url}}";
154
+ options.colorStatus = options.colorStatus || false;
155
+ options.expressFormat = options.expressFormat || false;
156
+ options.ignoreRoute = options.ignoreRoute || function () { return false; };
157
+ options.skip = options.skip || defaultSkip;
158
+
159
+ // Using mustache style templating
160
+ var template = _.template(options.msg, null, {
161
+ interpolate: /\{\{(.+?)\}\}/g
162
+ });
131
163
 
132
164
  return function (req, res, next) {
165
+ var currentUrl = req.originalUrl || req.url;
166
+ if (currentUrl && _.contains(ignoredRoutes, currentUrl)) return next();
167
+ if (options.ignoreRoute(req, res)) return next();
133
168
 
134
169
  req._startTime = (new Date);
135
170
 
@@ -139,6 +174,10 @@ function logger(options) {
139
174
  body: []
140
175
  };
141
176
 
177
+ req._routeBlacklists = {
178
+ body: []
179
+ };
180
+
142
181
  // Manage to get information from the response too, just like Connect.logger does:
143
182
  var end = res.end;
144
183
  res.end = function(chunk, encoding) {
@@ -147,10 +186,27 @@ function logger(options) {
147
186
  res.end = end;
148
187
  res.end(chunk, encoding);
149
188
 
150
- if(options.meta !== false) {
151
- var meta = {};
189
+ req.url = req.originalUrl || req.url;
190
+
191
+ if (options.statusLevels) {
192
+ if (res.statusCode >= 100) { options.level = "info"; }
193
+ if (res.statusCode >= 400) { options.level = "warn"; }
194
+ if (res.statusCode >= 500) { options.level = "error"; }
195
+ };
196
+
197
+ if (options.colorStatus || options.expressFormat) {
198
+ // Palette from https://github.com/expressjs/morgan/blob/master/index.js#L205
199
+ var statusColor = 'green';
200
+ if (res.statusCode >= 500) statusColor = 'red';
201
+ else if (res.statusCode >= 400) statusColor = 'yellow';
202
+ else if (res.statusCode >= 300) statusColor = 'cyan';
203
+ var coloredStatusCode = chalk[statusColor](res.statusCode);
204
+ }
152
205
 
153
- var bodyWhitelist;
206
+ var meta = {};
207
+
208
+ if(options.meta !== false) {
209
+ var bodyWhitelist, blacklist;
154
210
 
155
211
  requestWhitelist = requestWhitelist.concat(req._routeWhitelists.req || []);
156
212
  responseWhitelist = responseWhitelist.concat(req._routeWhitelists.res || []);
@@ -158,28 +214,44 @@ function logger(options) {
158
214
  meta.req = filterObject(req, requestWhitelist, options.requestFilter);
159
215
  meta.res = filterObject(res, responseWhitelist, options.responseFilter);
160
216
 
217
+ if (_.contains(responseWhitelist, 'body')) {
218
+ if (chunk) {
219
+ var isJson = (res._headers && res._headers['content-type']
220
+ && res._headers['content-type'].indexOf('json') >= 0);
221
+
222
+ meta.res.body = isJson ? JSON.parse(chunk) : chunk.toString();
223
+ }
224
+ }
225
+
161
226
  bodyWhitelist = req._routeWhitelists.body || [];
227
+ blacklist = _.union(bodyBlacklist, (req._routeBlacklists.body || []));
162
228
 
163
- if (bodyWhitelist) {
164
- meta.req.body = filterObject(req.body, bodyWhitelist, options.requestFilter);
165
- };
229
+ var filteredBody = null;
230
+
231
+ if ( req.body !== undefined ) {
232
+ if (blacklist.length > 0 && bodyWhitelist.length === 0) {
233
+ var whitelist = _.difference(_.keys(req.body), blacklist);
234
+ filteredBody = filterObject(req.body, whitelist, options.requestFilter);
235
+ } else {
236
+ filteredBody = filterObject(req.body, bodyWhitelist, options.requestFilter);
237
+ }
238
+ }
239
+
240
+ if (filteredBody) meta.req.body = filteredBody;
166
241
 
167
242
  meta.responseTime = res.responseTime;
168
243
  }
169
244
 
170
- // Using mustache style templating
171
- _.templateSettings = {
172
- interpolate: /\{\{(.+?)\}\}/g
173
- };
174
- var template = _.template(options.msg);
175
- var msg = template({req: req, res: res});
176
-
245
+ if(options.expressFormat) {
246
+ var msg = chalk.grey(req.method + " " + req.url || req.url)
247
+ + " " + chalk[statusColor](res.statusCode)
248
+ + " " + chalk.grey(res.responseTime+"ms");
249
+ } else {
250
+ var msg = template({req: req, res: res});
251
+ }
177
252
  // This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
178
- for(var i = 0; i < options.transports.length; i++) {
179
- var transport = options.transports[i];
180
- transport.log(options.level, msg, meta, function () {
181
- // Nothing to do here
182
- });
253
+ if (!options.skip(req, res)) {
254
+ options.winstonInstance.log(options.level, msg, meta);
183
255
  }
184
256
  };
185
257
 
@@ -189,13 +261,23 @@ function logger(options) {
189
261
 
190
262
  function ensureValidOptions(options) {
191
263
  if(!options) throw new Error("options are required by winston-middleware middleware");
192
- if(!options.transports || !(options.transports.length > 0)) throw new Error("transports are required by winston-middleware middleware");
193
- };
264
+ if(!((options.transports && (options.transports.length > 0)) || options.winstonInstance))
265
+ throw new Error("transports or a winstonInstance are required by winston-middleware middleware");
266
+ }
267
+
268
+ function ensureValidLoggerOptions(options) {
269
+ if (options.ignoreRoute && !_.isFunction(options.ignoreRoute)) {
270
+ throw new Error("`ignoreRoute` winston-middleware option should be a function");
271
+ }
272
+ }
194
273
 
195
274
  module.exports.errorLogger = errorLogger;
196
275
  module.exports.logger = logger;
197
276
  module.exports.requestWhitelist = requestWhitelist;
198
277
  module.exports.bodyWhitelist = bodyWhitelist;
278
+ module.exports.bodyBlacklist = bodyBlacklist;
199
279
  module.exports.responseWhitelist = responseWhitelist;
200
280
  module.exports.defaultRequestFilter = defaultRequestFilter;
201
281
  module.exports.defaultResponseFilter = defaultResponseFilter;
282
+ module.exports.defaultSkip = defaultSkip;
283
+ module.exports.ignoredRoutes = ignoredRoutes;
package/package.json CHANGED
@@ -1,5 +1,9 @@
1
1
  {
2
- "author": "Heapsource.com <npm@heapsource.com> (http://www.heapsource.com)",
2
+ "author": {
3
+ "name": "bithavoc",
4
+ "email": "im@bithavoc.io",
5
+ "url": "http://bithavoc.io"
6
+ },
3
7
  "name": "winston-middleware",
4
8
  "description": "express.js middleware for flatiron/winston",
5
9
  "keywords": [
@@ -10,25 +14,75 @@
10
14
  "log",
11
15
  "error",
12
16
  "handler",
13
- "middleware"
17
+ "middleware",
18
+ "colors"
14
19
  ],
15
- "version": "0.2.4",
20
+ "version": "1.0.0",
16
21
  "repository": {
17
- "url": "https://github.com/heapsource/winston-middleware.git"
22
+ "type": "git",
23
+ "url": "https://github.com/bithavoc/winston-middleware.git"
24
+ },
25
+ "bugs": {
26
+ "url": "http://github.com/bithavoc/winston-middleware/issues",
27
+ "email": "im@bithavoc.io"
18
28
  },
19
29
  "main": "index.js",
20
30
  "scripts": {
21
- "test": "vows --spec"
31
+ "test": "node_modules/.bin/mocha --reporter spec",
32
+ "test-travis": "node_modules/.bin/mocha --require blanket --reporter travis-cov",
33
+ "test-coverage": "node_modules/.bin/mocha --require blanket --reporter html-cov >| coverage.html || true"
34
+ },
35
+ "config": {
36
+ "travis-cov": {
37
+ "threshold": 100
38
+ },
39
+ "blanket": {
40
+ "pattern": [
41
+ "index.js"
42
+ ],
43
+ "data-cover-never": [
44
+ "node_modules",
45
+ "test"
46
+ ]
47
+ }
22
48
  },
23
49
  "dependencies": {
24
- "winston": "0.6.x",
25
- "underscore": "~1.5.2"
50
+ "chalk": "~0.4.0",
51
+ "underscore": "~1.5.2",
52
+ "winston": "~1.0.0"
26
53
  },
27
54
  "devDependencies": {
28
- "vows": "0.7.x"
55
+ "blanket": "~1.1.6",
56
+ "mocha": "~2.1.0",
57
+ "node-mocks-http": "~1.2.3",
58
+ "should": "~4.6.0",
59
+ "travis-cov": "~0.2.5"
29
60
  },
30
61
  "engines": {
31
- "node": "*"
62
+ "node": ">=0.6.0"
32
63
  },
33
- "license": "MIT"
64
+ "license": "MIT",
65
+ "contributors": [
66
+ {
67
+ "name": "Lars Jacob",
68
+ "url": "http://jaclar.net"
69
+ },
70
+ {
71
+ "name": "Jonathan Lomas",
72
+ "url": "http://floatinglomas.ca"
73
+ },
74
+ {
75
+ "name": "Xavier Damman",
76
+ "url": "http://xdamman.com"
77
+ },
78
+ {
79
+ "name": "Quentin Rossetti",
80
+ "email": "quentin.rossetti@gmail.com"
81
+ },
82
+ {
83
+ "name": "Robbie Trencheny",
84
+ "email": "me@robbiet.us",
85
+ "url": "http://robbie.io"
86
+ }
87
+ ]
34
88
  }