Repository: MiniProfiler/node
Branch: master
Commit: 3d131ef909c7
Files: 56
Total size: 65.0 KB
Directory structure:
gitextract_fz3xrl6x/
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .gitmodules
├── .npmignore
├── .travis.yml
├── README.md
├── lib/
│ ├── async-context.js
│ ├── client-parser.js
│ ├── middlewares/
│ │ ├── express.js
│ │ ├── hapi.js
│ │ └── koa.js
│ ├── miniprofiler.js
│ ├── storages/
│ │ ├── inmemory.js
│ │ └── redis.js
│ ├── ui.js
│ └── utils.js
├── package.json
└── tests/
├── assets-test.js
├── basic-test.js
├── client-test.js
├── concurrent-async-test.js
├── custom-config-test.js
├── index.js
├── render-test.js
├── servers/
│ ├── async-provider.js
│ ├── dummy-module.js
│ ├── dummy-provider.js
│ ├── express/
│ │ ├── async.js
│ │ ├── custom-config.js
│ │ ├── default.js
│ │ ├── index.js
│ │ ├── render.js
│ │ ├── unauthorized.js
│ │ └── unprofiled.js
│ ├── hapi/
│ │ ├── async.js
│ │ ├── custom-config.js
│ │ ├── default.js
│ │ ├── index.js
│ │ ├── render.js
│ │ ├── unauthorized.js
│ │ └── unprofiled.js
│ ├── index.js
│ ├── koa/
│ │ ├── async.js
│ │ ├── custom-config.js
│ │ ├── default.js
│ │ ├── index.js
│ │ ├── render.js
│ │ ├── unauthorized.js
│ │ └── unprofiled.js
│ └── views/
│ └── index.pug
├── share-test.js
├── step-test.js
├── timequery-test.js
├── unauthorized-test.js
└── unprofiled-test.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
ui
coverage
================================================
FILE: .eslintrc.json
================================================
{
"extends": "eslint:recommended",
"env": {
"node": true,
"es6": true,
"mocha": true
},
"rules": {
"semi": [2, "always"],
"require-yield": 0,
"strict": ["error", "global"],
"no-unused-vars": ["error", { "vars": "all", "args": "none" }],
"quotes": ["error", "single", { "avoidEscape": true } ],
"space-before-function-paren": ["error", "never"]
}
}
================================================
FILE: .gitignore
================================================
logs
*.log
npm-debug.log*
pids
*.pid
*.seed
*.rdb
*.DS_STORE
lib-cov
coverage
.nyc_output
.grunt
.lock-wscript
build/Release
node_modules
jspm_packages
.npm
.node_repl_history
================================================
FILE: .gitmodules
================================================
[submodule "ui"]
path = ui
url = https://github.com/MiniProfiler/ui.git
================================================
FILE: .npmignore
================================================
coverage
tests
node_modules
examples
.travis.yml
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- "8"
- "stable"
sudo: required
services:
- docker
before_script:
- npm run start-services
- npm run lint
- sleep 3
after_script:
- npm run coverage
- npm run check-coverage
- npm run update-coveralls
notifications:
email:
on_success: never
on_failure: change
================================================
FILE: README.md
================================================
# MiniProfiler for Node.js
Node.js implementation of Stack Exchange's MiniProfiler
[](https://www.npmjs.com/package/miniprofiler)
[](https://travis-ci.org/MiniProfiler/node)
[](https://coveralls.io/github/MiniProfiler/node?branch=master)


## Demonstration
Visit [http://miniprofiler-demo.herokuapp.com](http://miniprofiler-demo.herokuapp.com) for a live demonstration.
## Installation
```bash
$ npm install miniprofiler
```
You can hook up your application with any of the following packages are available on npm:
| Name | About | Version |
|-----------|-----------|-----------|
| `miniprofiler-http` | Profile http(s) requests | [](https://www.npmjs.com/package/miniprofiler-http) |
| `miniprofiler-pg` | Profile [pg](https://www.npmjs.com/package/pg) queries | [](https://www.npmjs.com/package/miniprofiler-pg) |
| `miniprofiler-redis`| Profile [redis](https://www.npmjs.com/package/redis) calls | [](https://www.npmjs.com/package/miniprofiler-redis) |
## Usage
### Simple usage with express.js
`server.js`
```javascript
var express = require('express')
, miniprofiler = require('miniprofiler')
, app = express();
app.set('view engine', 'pug');
app.use(miniprofiler.express());
app.get('/', function(req, res) {
req.miniprofiler.step('Step 1', function() {
req.miniprofiler.step('Step 2', function() {
res.render('index');
});
});
});
app.listen(8080);
```
`index.pug`
```javascript
doctype html
html
head
title MiniProfiler Node.js Example
body
h1 Home Page
| !{miniprofiler.include()}
```
When visiting `localhost:8080`, you should see this.

## API
### `miniprofiler.{framework}([options])`
Replace `{framework}` with koa, express or hapi.
This function returns a framework specific middleware that is responsible for initializing MiniProfiler on each request.
#### `options` object properties
| Property | Default | Description |
|-----------|-----------|-------------|
| enable | Always returns true | function(req, res) => boolean; this function is used to determine if the profiler should be enabled for the current request |
| authorize | Always returns true | function(req, res) => boolean; this function is used to determine if the current request should be able to see the profiling results |
### `miniprofiler.{framework}.for([provider])`
`provider` is a call for any of the supported providers listed [here](#installation).
### `miniprofiler.configure([options])`
#### `options` object properties
| Property | Default | Description |
|-----------|-----------|-------------|
| storage | InMemoryStorage({ max: 100, maxAge: 1000 \* 60 \* 60 }) | InMemoryStorage or RedisStorage; used to store or fetch a string JSON blob of profiling information |
| ignoredPaths | [ ] | string array ; any request whose `url` property is in ignoredPaths will not be profiled |
| trivialDurationThresholdMilliseconds | 2.5 | double ; any step lasting longer than this will be considered trivial, and hidden by default |
| popupShowTimeWithChildren | false | boolean ; whether or not to include the "time with children" column |
| popupRenderPosition | left | 'left', 'right', 'bottomLeft' or 'bottomRight' ; which side of the screen to display timings on |
#### `options.storage` examples
#### InMemoryStorage
```
miniprofiler.configure({
storage: miniprofiler.storage.InMemoryStorage({ lruCacheOptions });
})
```
Refer to [lru-cache](https://www.npmjs.com/package/lru-cache) documentation for `lruCacheOptions`.
#### RedisStorage
```
miniprofiler.configure({
storage: miniprofiler.storage.RedisStorage(client);
})
```
Where `client` is an instance of [redis.createClient](https://www.npmjs.com/package/redis).
================================================
FILE: lib/async-context.js
================================================
'use strict';
const asyncHooks = require('async_hooks');
class AsyncContext {
constructor() {
this.map = new Map();
asyncHooks.createHook({
init: (id, _type, triggerId) => {
if (this.map.has(triggerId))
this.map.set(id, this.map.get(triggerId));
},
destroy: (id) => this.map.delete(id)
}).enable();
}
get() {
const id = asyncHooks.executionAsyncId();
if (this.map.has(id))
return this.map.get(id);
}
set(val) {
this.map.set(asyncHooks.executionAsyncId(), val);
}
}
module.exports = new AsyncContext();
================================================
FILE: lib/client-parser.js
================================================
'use strict';
var _ = require('./utils.js');
let insertInOrder = (array, timing) => {
if (timing.Start <= 0)
return;
for(let key in array) {
if (timing.Start <= array[key].Start) {
return array.splice(key, 0, timing);
}
}
return array.push(timing);
};
module.exports = (postData) => {
let preffix = 'clientPerformance[timing][';
let postDataTimings = { };
let clientTimings = [ ];
let navigationStart = 0;
for(let postDataKey in postData) {
if (postDataKey.startsWith(preffix)) {
let key = postDataKey.substring(preffix.length, postDataKey.length - 1);
if (key == 'navigationStart')
navigationStart = parseInt(postData[postDataKey]);
else
postDataTimings[key] = parseInt(postData[postDataKey]);
}
}
if (!navigationStart)
return null;
for(let key in postDataTimings) {
if (key.endsWith('Start')) {
let eventName = key.slice(0, -5);
let eventStartTime = postDataTimings[`${eventName}Start`];
let eventEndTime = postDataTimings[`${eventName}End`];
let timing = {
Name: _.toTitleCase(eventName),
Start: eventStartTime - navigationStart,
Duration: eventEndTime - eventStartTime
};
if (!timing.Duration) {
timing.Name = _.toTitleCase(`${eventName}Start`);
timing.Duration = -1;
}
insertInOrder(clientTimings, timing);
} else if (!key.endsWith('End')) {
insertInOrder(clientTimings, {
Name: _.toTitleCase(key),
Start: postDataTimings[key] - navigationStart,
Duration: -1
});
}
}
return {
RedirectCount: parseInt(postData['clientPerformance[navigation][redirectCount]']),
Timings: clientTimings
};
};
================================================
FILE: lib/middlewares/express.js
================================================
'use strict';
const asyncContext = require('../async-context');
module.exports = {
buildMiddleware: function(provider) {
return function(req, res, next) {
provider.handler(req, res, next);
};
},
mainMiddleware: function(enable, authorize, handleRequest, cls) {
return function(req, res, next) {
handleRequest(enable, authorize, req, res).then((handled) => {
res.locals.miniprofiler = req.miniprofiler;
asyncContext.set(req.miniprofiler);
Object.defineProperty(req, 'miniprofiler', { get: () => asyncContext.get() });
var render = res.render;
res.render = function() {
var renderArguments = arguments;
req.miniprofiler.step(`Render: ${arguments[0]}`, function() {
render.apply(res, renderArguments);
});
};
if (!handled)
next();
}).catch(next);
};
}
};
================================================
FILE: lib/middlewares/hapi.js
================================================
'use strict';
const asyncContext = require('../async-context');
module.exports = {
buildMiddleware: function(provider) {
var plugin = {
register: (server, options, next) => {
server.ext('onRequest', function(request, reply) {
provider.handler(request.raw.req, request.raw.res, () => {
return reply.continue();
});
});
next();
}
};
plugin.register.attributes = {
name: `miniprofiler-hapi-${provider.name}`,
version: require('../../package.json').version
};
return plugin;
},
mainMiddleware: function(enable, authorize, handleRequest) {
var plugin = {
register: (server, options, next) => {
server.ext('onRequest', function(request, reply) {
handleRequest(enable, authorize, request.raw.req, request.raw.res).then((handled) => {
asyncContext.set(request.raw.req.miniprofiler);
Object.defineProperty(request.app, 'miniprofiler', { get: () => asyncContext.get() });
Object.defineProperty(request.raw.req, 'miniprofiler', { get: () => asyncContext.get() });
if (!handled)
reply.continue();
});
});
next();
}
};
plugin.register.attributes = {
name: 'miniprofiler-hapi',
version: require('../../package.json').version
};
//That's a bad monkey patch, didn't like it, needs refactor...
plugin.vision = (server) => {
var view = server._replier._decorations['view'];
server._replier._decorations['view'] = function(template, context, options) {
var viewArguments = arguments;
this.request.raw.req.miniprofiler.step(`Render: ${template}`, () => {
return view.apply(this, viewArguments);
});
};
};
return plugin;
}
};
================================================
FILE: lib/middlewares/koa.js
================================================
'use strict';
const asyncContext = require('../async-context');
module.exports = {
buildMiddleware: function(provider) {
return function *(next) {
yield new Promise((resolve, reject) => {
provider.handler(this.req, this.res, resolve);
});
yield next;
};
},
mainMiddleware: function(enable, authorize, handleRequest) {
return function *(next) {
var handled = yield handleRequest(enable, authorize, this.req, this.res);
asyncContext.set(this.req.miniprofiler);
Object.defineProperty(this.state, 'miniprofiler', { get: () => asyncContext.get() });
Object.defineProperty(this.req, 'miniprofiler', { get: () => asyncContext.get() });
if (this.render) {
var render = this.render;
this.render = function() {
return new Promise((resolve, reject) => {
var renderArguments = arguments;
this.req.miniprofiler.step(`Render: ${arguments[0]}`, function() {
render.apply(this, renderArguments);
resolve();
});
});
};
}
if (!handled)
yield next;
};
}
};
================================================
FILE: lib/miniprofiler.js
================================================
'use strict';
/*
* MiniProfiler implementation for node.js.
*
* Apache License, Version 2.0
*
* Kevin Montrose, 2013 @kevin-montrose
* Matt Jibson, 2013 @mjibsonF
* Guilherme Oenning, 2016 @goenning
*/
var _ = require('./utils.js');
var qs = require('querystring');
var url = require('url');
var ui = require('./ui.js');
var clientParser = require('./client-parser.js');
const hostname = require('os').hostname;
var ignoredPaths = [];
var trivialDurationThresholdMilliseconds = 2.5;
var popupShowTimeWithChildren = false;
var popupRenderPosition = 'left';
var resourcePath = '/mini-profiler-resources/';
exports.storage = {
InMemoryStorage: require('./storages/inmemory.js'),
RedisStorage: require('./storages/redis.js')
};
var storage = new exports.storage.InMemoryStorage({ max: 100, maxAge: 1000 * 60 * 60 });
exports.configure = configure;
configure();
for (let framework of ['koa', 'express', 'hapi']) {
let func = require(`./middlewares/${framework}.js`);
exports[framework] = function(options) {
options = options || {};
if (!options.enable) options.enable = () => { return true; };
if (!options.authorize) options.authorize = () => { return true; };
return func.mainMiddleware(options.enable, options.authorize, handleRequest);
};
exports[framework].for = func.buildMiddleware;
}
var version = require('../package.json').version;
var contentTypes = {
css: 'text/css',
js: 'text/javascript',
tmpl: 'text/html; charset=utf-8'
};
function getPath(req) {
return url.parse(req.url).path;
}
function handleRequest(enable, authorize, req, res) {
return new Promise((resolve, reject) => {
var enabled = enable(req, res);
var authorized = authorize(req, res);
var requestPath = url.parse(req.url).pathname;
for (let ignoredPath of ignoredPaths) {
if (requestPath.startsWith(ignoredPath)) {
enabled = false;
break;
}
}
if (!requestPath.startsWith(resourcePath)) {
var extension = startProfiling(req, enabled, authorized);
if (enabled) {
res.on('finish', () => {
stopProfiling(extension, req);
});
res.setHeader('X-MiniProfiler-Ids', `["${extension.id}"]`);
}
return resolve(false);
}
if (!authorized) {
res.writeHead(401, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('');
return resolve(true);
}
if (!enabled) {
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('MiniProfiler is disabled');
return resolve(true);
}
var segments = _.compact(requestPath.split('/'));
var lastPathSegment = segments[segments.length - 1];
var handler = (lastPathSegment == 'results') ? results : assets;
handler(req, res, lastPathSegment, (result) => {
res.writeHead(result.status, { 'Content-Type': result.type });
res.end(result.body);
resolve(true);
});
});
}
function assets(req, res, lastPathSegment, done) {
ui.readFile(lastPathSegment, function(err, data) {
if (err) {
done({
type: 'text/plain; charset=utf-8',
status: 404,
body: 'Resource unavailable.'
});
} else {
var rs = lastPathSegment.split('.');
res.setHeader('Cache-Control', 'public, max-age=31557600');
done({
type: contentTypes[rs[rs.length - 1]],
status: 200,
body: data
});
}
});
}
function results(req, res, lastPathSegment, done) {
var proc = function(post, done) {
var query = url.parse(req.url, true).query;
var id = post.id || query.id;
var popup = post.popup || query.popup;
var timing = (req.method === 'POST') ? clientParser(post) : null;
storage.get(id, (err, data) => {
if (!data) {
done({
type: 'text/plain; charset=utf-8',
status: 404,
body: `Id '${id}' not found.`
});
return;
}
var json = JSON.parse(data);
if (timing) {
json.ClientTimings = timing;
data = JSON.stringify(json);
storage.set(id, data);
}
if (popup == '1') {
done({
type: 'application/json',
status: 200,
body: data
});
return;
}
done({
type: 'text/html; charset=utf-8',
status: 200,
body: ui.share({
name: json.Name,
duration: json.DurationMilliseconds,
path: resourcePath,
json: data,
includes: include(id),
version: version
})
});
});
};
var body = '';
req.on('data', function(data) {
body += data;
});
req.on('end', function() {
var post = qs.parse(body);
proc(post, done);
});
}
function include(id) {
return ui.partial({
path: resourcePath,
position: popupRenderPosition,
showChildren: popupShowTimeWithChildren,
trivialMilliseconds: trivialDurationThresholdMilliseconds,
version: version,
currentId: id,
ids: id,
showTrivial: true,
maxTracesToShow: 15,
showControls: true,
authorized: true,
toggleShortcut: '',
startHidden: false
});
}
/*
* Setup profiling. This function may only be called once, subsequent calls are ignored.
*
* This must be called before the first call to startProfiling.
*
* options is an optional object, which can have the following fields:
* - storage: InMemoryStorage or RedisStorage; used to store or fetch a string JSON blob of profiling information
* - ignoredPaths: string array ; any request whose `url` property is in ignoredPaths will not be profiled
* - trivialDurationThresholdMilliseconds: double ; any step lasting longer than this will be considered trivial, and hidden by default
* - popupShowTimeWithChildren: boolean ; whether or not to include the "time with children" column
* - popupRenderPosition: 'left', 'right', 'bottomLeft', 'bottomRight' ; which side of the screen to display timings on
* - resourcePath: string ; if your site root is in a subdirectory, specify here, e.g., /siteroot
*/
function configure(options) {
options = options || {};
ignoredPaths = options.ignoredPaths || ignoredPaths;
trivialDurationThresholdMilliseconds = options.trivialDurationThresholdMilliseconds || trivialDurationThresholdMilliseconds;
popupShowTimeWithChildren = options.popupShowTimeWithChildren || popupShowTimeWithChildren;
popupRenderPosition = options.popupRenderPosition || popupRenderPosition;
storage = options.storage || storage;
resourcePath = `${options.resourcePath ? options.resourcePath.replace(/\/$/, '') : ''}${resourcePath}`;
}
/*
* Begins profiling the given request.
*/
function startProfiling(request, enabled, authorized) {
var currentRequestExtension = {
enabled: enabled,
authorized: authorized
};
if (enabled) {
var path = getPath(request);
currentRequestExtension.id = _.uuid();
currentRequestExtension.startDate = Date.now();
currentRequestExtension.startTime = process.hrtime();
currentRequestExtension.stopTime = null;
currentRequestExtension.stepGraph = makeStep(path, currentRequestExtension.startTime, null);
currentRequestExtension.customTimings = {};
}
currentRequestExtension.timeQuery = function() {
var args = Array.prototype.slice.call(arguments, enabled ? 0 : 3);
if (enabled) {
args.unshift(currentRequestExtension);
timeQuery.apply(this, args);
} else {
arguments[2].apply(this, args);
}
};
currentRequestExtension.startTimeQuery = function(type, query) {
return startTimeQuery.call(this, currentRequestExtension, type, query);
};
currentRequestExtension.stopTimeQuery = function(timing) {
return stopTimeQuery.call(this, timing);
};
currentRequestExtension.step = function(name, call) {
if (enabled) {
step(name, request, call);
} else {
call();
}
};
currentRequestExtension.include = function() {
return enabled && authorized ? include(currentRequestExtension.id) : '';
};
request.miniprofiler = currentRequestExtension;
return currentRequestExtension;
}
/*
* Stops profiling the given request.
*/
function stopProfiling(extension, request) {
var time = process.hrtime();
extension.stopTime = time;
extension.stepGraph.stopTime = time;
var json = describePerformance(extension, request);
storage.set(extension.id, JSON.stringify(json));
}
/*
* Wraps an invokation of `call` in a step named `name`.
*
* You should only use this method directly in cases when calls to addProfiling won't suffice.
*/
function step(name, request, call) {
var time = process.hrtime();
var extension = request.miniprofiler;
var newStep = makeStep(name, time, extension.stepGraph);
extension.stepGraph.steps.push(newStep);
extension.stepGraph = newStep;
var result;
if (call.length) {
result = call(() => {
unstep(name, request);
});
} else {
try {
result = call();
} finally {
unstep(name, request);
}
}
return result;
}
/*
* Called to time a query, like to SQL or Redis, that completes with a callback
*
* `type` can be any string, it is used to group query types in timings.
* `query` is a string representing the query, this is what is recorded as having run.
*
* `executeFunction` is invoked with any additional parameters following it.
*
* Any function passed as a parameter to `executeFunction` will be instrumented to detect
* when the query has completed. Implicitly, any execution of a callback is considered
* to have ended the query.
*/
function timeQuery(extension, type, query, executeFunction) {
var timing = startTimeQuery(extension, type, query);
var params = Array.prototype.slice.call(arguments, 4);
for (var i = 0; i < params.length; i++) {
if (_.isFunction(params[i])) {
var param = params[i];
params[i] = function() {
extension.stopTimeQuery(timing);
var ret = param.apply(this, arguments);
return ret;
};
}
}
var ret = executeFunction.apply(this, params);
return ret;
}
function stopTimeQuery(timing) {
timing.stopTime = process.hrtime();
}
function startTimeQuery(extension, type, query) {
var time = process.hrtime();
var startDate = Date.now();
extension.stepGraph.customTimings[type] = extension.stepGraph.customTimings[type] || [];
var customTiming = {
id: _.uuid(),
executeType: type,
commandString: _.escape(query),
startTime: time,
startDate: startDate,
callStack: new Error().stack
};
extension.stepGraph.customTimings[type].push(customTiming);
return customTiming;
}
function unstep(name, request) {
var time = process.hrtime();
var extension = request.miniprofiler;
extension.stepGraph.stopTime = time;
// step back up
extension.stepGraph = extension.stepGraph.parent;
}
function describePerformance(root, request) {
var ret = {};
ret.Id = root.id;
ret.Name = getPath(request);
ret.Started = root.startDate;
ret.MachineName = hostname();
ret.Root = describeTimings(root.stepGraph, root.stepGraph);
ret.ClientTimings = null;
ret.DurationMilliseconds = ret.Root.DurationMilliseconds;
return ret;
}
function diff(start, stop) {
var deltaSecs = stop[0] - start[0];
var deltaNanoSecs = stop[1] - start[1];
var elapsedMs = deltaSecs * 1000 + deltaNanoSecs / 1000000;
return elapsedMs;
}
function callStack(stack) {
var sp = stack.split('\n');
var ret = [];
for (var i = 2; i < sp.length; i++) {
var st = sp[i].trim().split(' ');
ret.push(st[1]);
}
return ret.join(' ');
}
function describeTimings(timing, root) {
var id = _.uuid();
var name = timing.name;
var elapsedMs = diff(timing.startTime, timing.stopTime);
var sinceRootMs = diff(root.startTime, timing.startTime);
var customTimings = describeCustomTimings(timing.customTimings, root);
var children = [];
for (var i = 0; i < timing.steps.length; i++) {
var step = timing.steps[i];
children.push(describeTimings(step, root));
}
return {
Id: id,
Name: name,
DurationMilliseconds: elapsedMs,
StartMilliseconds: sinceRootMs,
Children: children,
CustomTimings: customTimings
};
}
function describeCustomTimings(customTimings, root) {
var ret = {};
for (var prop in customTimings) {
var arr = customTimings[prop];
var retArr = [];
for (var i = 0; i < arr.length; i++) {
var timing = {};
timing.Id = arr[i].id;
timing.ExecuteType = arr[i].executeType;
timing.CommandString = arr[i].commandString;
timing.StartMilliseconds = diff(root.startTime, arr[i].startTime);
timing.DurationMilliseconds = diff(arr[i].startTime, arr[i].stopTime);
timing.StackTraceSnippet = callStack(arr[i].callStack);
retArr.push(timing);
}
ret[prop] = retArr;
}
return ret;
}
function makeStep(name, time, parent) {
return { name: name, startTime: time, stopTime: null, parent: parent, steps: [], customTimings: {} };
}
================================================
FILE: lib/storages/inmemory.js
================================================
'use strict';
var LRU = require('lru-cache');
let miniprofilerHashKey = '_miniprofiler_';
function InMemoryStorage(options) {
this.key = function(id) {
return `${miniprofilerHashKey}${id}`;
};
this.cache = LRU(options);
this.get = function(id, callback) {
var data = this.cache.get(this.key(id));
if (data)
callback(null, data);
else
callback(new Error(`Id '${id}' not found.`));
};
this.set = function(id, json) {
this.cache.set(this.key(id), json);
};
}
module.exports = InMemoryStorage;
================================================
FILE: lib/storages/redis.js
================================================
'use strict';
let miniprofilerHashKey = '_miniprofiler_';
function RedisStorage(redisClient, maxAge) {
this.maxAge = maxAge || 3600;
this.key = function(id) {
return `${miniprofilerHashKey}${id}`;
};
this.get = function(id, callback) {
redisClient.get(this.key(id), callback);
};
this.set = function(id, json) {
let key = this.key(id);
redisClient.set(key, json, (err, data) => {
redisClient.expire(key, this.maxAge);
});
};
}
module.exports = RedisStorage;
================================================
FILE: lib/ui.js
================================================
'use strict';
const fileStore = { };
const fs = require('fs');
const path = require('path');
const _ = require('./utils.js');
const includesDir = path.join(__dirname, '../ui');
const readFile = (name, callback) => {
if (fileStore[name]) {
callback(null, fileStore[name]);
} else {
fs.readFile(path.join(includesDir, name), 'utf-8', (err, text) => {
fileStore[name] = text;
callback(err, text);
});
}
};
const templates = {
partial: _.template(fs.readFileSync(path.join(includesDir, 'include.partial.html')).toString()),
share: _.template(fs.readFileSync(path.join(includesDir, 'share.html')).toString())
};
const partial = (options) => templates.partial(options);
const share = (options) => templates.share(options);
module.exports = { readFile, partial, share };
================================================
FILE: lib/utils.js
================================================
'use strict';
const isFunction = (obj) => {
return typeof obj == 'function' || false;
};
const tagsToReplace = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'`': '`'
};
const escape = (str) => {
return str.replace(/[&<>]/g, function(tag) {
return tagsToReplace[tag] || tag;
});
};
const compact = (arr) => {
return arr.filter((v) => v);
};
const uuid = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
};
const toTitleCase = (str) => {
return str.replace(/ /g,'').split(/(?=[A-Z])/).join(' ').replace(/^.| ./g, (m) => {
return m.toUpperCase();
});
};
const template = (content) => {
return (options) => {
return content.replace(/{(.+?)}/g, (match, key) => {
return options[key];
});
};
};
module.exports = {
isFunction, escape, compact, uuid, toTitleCase, template
};
================================================
FILE: package.json
================================================
{
"name": "miniprofiler",
"version": "2.0.0",
"description": "A simple but effective mini-profiler.",
"main": "lib/miniprofiler.js",
"scripts": {
"start-services": "docker run -d -p 6060:6379 redis",
"lint": "eslint .",
"test": "mocha tests/ -c",
"coverage": "istanbul cover ./node_modules/mocha/bin/_mocha -- tests/ -R spec",
"check-coverage": "istanbul check-coverage --statements 95 --branches 95 --functions 95 --lines 95",
"update-coveralls": "cat coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js"
},
"repository": {
"type": "git",
"url": "https://github.com/MiniProfiler/node.git"
},
"bugs": {
"url": "http://github.com/MiniProfiler/node/issues"
},
"author": "Guilherme Oenning <oenning.ti@gmail.com> (http://goenning.net/)",
"contributors": [
"Matt Jibson <matt.jibson@gmail.com> (https://mattjibson.com/)",
"Kevin Montrose"
],
"license": "Apache-2.0",
"readmeFilename": "README.md",
"dependencies": {
"lru-cache": "^4.0.1"
},
"tags": [
"profiler",
"performance",
"profiling",
"timing",
"web profiling"
],
"devDependencies": {
"chai": "^3.5.0",
"coveralls": "^2.11.11",
"docker-ip": "^2.0.1",
"eslint": "^6.6.0",
"express": "^4.13.4",
"hapi": "^13.5.0",
"istanbul": "^0.4.3",
"koa": "^1.2.1",
"koa-route": "^2.4.2",
"koa-views": "^4.1.0",
"debug": "^2.6.1",
"mocha": "^2.5.3",
"pug": "^2.0.0-beta2",
"redis": "^3.1.1",
"request": "^2.73.0",
"vision": "^4.1.0"
}
}
================================================
FILE: tests/assets-test.js
================================================
'use strict';
var expect = require('chai').expect;
var fs = require('fs');
module.exports = function(server) {
describe('Assets Tests', function() {
before(server.setUp.bind(null, 'default'));
after(server.tearDown);
var files = [
'includes.css',
'includes.css',
'includes.tmpl',
'includes.js'
];
files.forEach((file) => {
it(`Should return ${file} file`, function(done) {
server.get(`/mini-profiler-resources/${file}`, (err, response, body) => {
fs.readFile(`./ui/${file}`, 'utf-8', (err, content) => {
expect(body).to.be.equal(content);
done();
});
});
});
});
it('Unknown file should return 404', function(done) {
server.get('/mini-profiler-resources/unknown.js', (err, response, body) => {
expect(response.statusCode).to.be.equal(404);
expect(body).to.be.equal('Resource unavailable.');
expect(response.headers['content-type']).to.be.equal('text/plain; charset=utf-8');
done();
});
});
});
};
================================================
FILE: tests/basic-test.js
================================================
'use strict';
var expect = require('chai').expect;
var pkg = require('../package.json');
module.exports = function(server) {
describe('Basic Tests', function() {
before(server.setUp.bind(null, 'default'));
after(server.tearDown);
it('Profiled routes should always return Profiler ID', function(done) {
server.get('/', (err, response) => {
expect(response.headers).to.include.keys('x-miniprofiler-ids');
done();
});
});
it('Index page should include MiniProfiler javascript', function(done) {
server.get('/', (err, response, body) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
expect(body.trim()).to.be.equal(`<script async type="text/javascript" id="mini-profiler" src="/mini-profiler-resources/includes.js?v=${pkg.version}" data-version="${pkg.version}" data-path="/mini-profiler-resources/" data-current-id="${ids[0]}" data-ids="${ids[0]}" data-position="left" data-trivial="true" data-children="false" data-max-traces="15" data-controls="true" data-authorized="true" data-toggle-shortcut="" data-start-hidden="false" data-trivial-milliseconds="2.5"></script>`);
done();
});
});
it('Should return url parameters on results response', function(done) {
server.get('/?key1=value1&key2=value2', (err, response, body) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.get(`/mini-profiler-resources/results?id=${ids[0]}&popup=1`, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/?key1=value1&key2=value2');
expect(result.Root.Children).to.be.empty;
done();
});
});
});
});
};
================================================
FILE: tests/client-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Client Timing Tests', function() {
before(server.setUp.bind(null, 'default'));
after(server.tearDown);
it('should return client timing data that is sent on POST', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
server.post('/mini-profiler-resources/results', {
id: ids[0],
popup: 1,
clientPerformance: {
navigation: {
redirectCount: 0
},
timing: {
navigationStart: 1000,
responseEnd: 1014,
loadEventStart: 1080,
requestStart: 1001,
secureConnectionStart: 0,
loadEventEnd: 1112,
responseStart: 1002,
'First Paint Time':1200
}
}
}, (err, response, body) => {
var data = JSON.parse(body);
expect(data.ClientTimings).to.be.deep.equal({
RedirectCount: 0,
Timings: [{
Name: 'Request Start',
Start: 1,
Duration: -1
},{
Name: 'Response',
Start: 2,
Duration: 12
},{
Name: 'Load Event',
Start: 80,
Duration: 32
},{
Name: 'First Paint Time',
Start: 200,
Duration: -1
}]
});
done();
});
});
});
it('should not return client timing when data is not sent via POST', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
server.post('/mini-profiler-resources/results', {
id: ids[0],
popup: 1
}, (err, response, body) => {
var data = JSON.parse(body);
expect(data.ClientTimings).to.be.null;
done();
});
});
});
});
};
================================================
FILE: tests/concurrent-async-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Concurrent Async Requests', function() {
before(server.setUp.bind(null, 'async'));
after(server.tearDown);
it('Each profile runs on its own context', function(done) {
let countDone = 0;
const partialDone = () => { if (++countDone === 2) done(); };
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results/', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Root.CustomTimings.async).to.have.lengthOf(2);
partialDone();
});
});
server.get('/?once=true', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results/', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Root.CustomTimings.async).to.have.lengthOf(1);
partialDone();
});
});
});
});
};
================================================
FILE: tests/custom-config-test.js
================================================
'use strict';
var expect = require('chai').expect;
var pkg = require('../package.json');
module.exports = function(server) {
describe('Custom Configuration Tests', function() {
this.timeout(5000);
before(server.setUp.bind(null, 'custom-config'));
after(server.tearDown);
it('should include MiniProfiler javascript with custom settings', function(done) {
server.get('/', (err, response, body) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
expect(body.trim()).to.be.equal(`<script async type="text/javascript" id="mini-profiler" src="/mini-profiler-resources/includes.js?v=${pkg.version}" data-version="${pkg.version}" data-path="/mini-profiler-resources/" data-current-id="${ids[0]}" data-ids="${ids[0]}" data-position="right" data-trivial="true" data-children="false" data-max-traces="15" data-controls="true" data-authorized="true" data-toggle-shortcut="" data-start-hidden="false" data-trivial-milliseconds="2.5"></script>`);
done();
});
});
it('should get/set timing from redis storage', function(done) {
server.get('/?key=value', (err, response, body) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/?key=value');
expect(result.Root.Children).to.be.empty;
done();
});
});
});
it('should not get timing about from ignored paths', function(done) {
server.get('/hidden', (err, response, body) => {
expect(response.headers).to.not.include.keys('x-miniprofiler-ids');
done();
});
});
});
};
================================================
FILE: tests/index.js
================================================
'use strict';
var fs = require('fs');
var servers = require('./servers');
var testCases = fs.readdirSync('./tests').filter((file) => file.endsWith('-test.js'));
for (var server of servers) {
describe(`[${server.framework}]`, function() {
for (var testCase of testCases) {
require(`./${testCase}`)(server);
}
});
}
================================================
FILE: tests/render-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Render Tests', function() {
before(server.setUp.bind(null, 'render'));
after(server.tearDown);
it('Should add render step', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/');
expect(result.Root.Children).to.have.lengthOf(1);
expect(result.Root.Children[0].Name).to.equal('Render: index');
expect(result.Root.Children[0].Children).to.be.empty;
done();
});
});
});
it('Should add render step inside another step', function(done) {
server.get('/inside-step', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/inside-step');
expect(result.Root.Children).to.have.lengthOf(1);
expect(result.Root.Children[0].Name).to.equal('Step 1');
expect(result.Root.Children[0].Children).to.have.lengthOf(1);
expect(result.Root.Children[0].CustomTimings).to.have.property('custom');
expect(result.Root.Children[0].CustomTimings.custom).to.have.lengthOf(1);
expect(result.Root.Children[0].Children[0].Name).to.be.equal('Render: index');
expect(result.Root.Children[0].Children[0].Children).to.be.empty;
done();
});
});
});
});
};
================================================
FILE: tests/servers/async-provider.js
================================================
'use strict';
module.exports = function(obj) {
return {
name: 'dummy-async',
handler: function(req, res, next) {
obj.asyncFn = function() {
const timing = req.miniprofiler.startTimeQuery('async', 'dummy call');
return new Promise(resolve => {
setTimeout(() => {
req.miniprofiler.stopTimeQuery(timing);
resolve();
}, 25);
});
};
next();
}
};
};
================================================
FILE: tests/servers/dummy-module.js
================================================
'use strict';
module.exports = {
asyncFn: () => Promise.resolve()
};
================================================
FILE: tests/servers/dummy-provider.js
================================================
'use strict';
module.exports = function() {
return {
name: 'dummy',
handler: function(req, res, next) {
next();
}
};
};
================================================
FILE: tests/servers/express/async.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var dummyModule = require('../dummy-module');
var express = require('express');
var app = express();
app.use(miniprofiler.express());
app.use(miniprofiler.express.for(require('../async-provider.js')(dummyModule)));
app.get('/', (req, res) => {
dummyModule.asyncFn().then(() => {
Promise.resolve(req.query.once ? undefined : dummyModule.asyncFn())
.then(() => res.send(res.locals.miniprofiler.include()));
});
});
module.exports = app;
================================================
FILE: tests/servers/express/custom-config.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var express = require('express');
var ip = require('docker-ip');
var redis = require('redis');
var client = redis.createClient(6060, ip());
var app = express();
miniprofiler.configure({
popupRenderPosition: 'right',
storage: new miniprofiler.storage.RedisStorage(client),
ignoredPaths: [ '/hidden' ]
});
app.use(miniprofiler.express());
app.get('/', (req, res) => {
res.send(res.locals.miniprofiler.include());
});
app.get('/hidden', (req, res) => {
res.send('This won\'t be profiled.');
});
module.exports = app;
================================================
FILE: tests/servers/express/default.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var express = require('express');
var app = express();
app.use(miniprofiler.express());
app.use(miniprofiler.express.for(require('../dummy-provider.js')()));
app.get('/', (req, res) => {
res.send(res.locals.miniprofiler.include());
});
app.get('/step', (req, res) => {
req.miniprofiler.step('Step', () => {
res.send(res.locals.miniprofiler.include());
});
});
app.get('/step-two', (req, res) => {
req.miniprofiler.step('Step 1', () => {
req.miniprofiler.step('Step 2', () => {
res.send(res.locals.miniprofiler.include());
});
});
});
app.get('/step-parallel', (req, res) => {
var count = 0;
var finish = () => {
if (++count == 2)
res.send(res.locals.miniprofiler.include());
};
req.miniprofiler.step('Step 1', finish);
req.miniprofiler.step('Step 2', finish);
});
app.get('/js-sleep', function(req, res) {
req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {
res.send(res.locals.miniprofiler.include());
}, 50);
});
app.get('/js-sleep-start-stop', function(req, res) {
var timing = req.miniprofiler.startTimeQuery('custom', 'Sleeping...');
setTimeout(function() {
req.miniprofiler.stopTimeQuery(timing);
res.send(res.locals.miniprofiler.include());
}, 50);
});
module.exports = app;
================================================
FILE: tests/servers/express/index.js
================================================
'use strict';
var server;
module.exports = {
start: function(name, port, done) {
var app = require(`./${name}.js`);
server = app.listen(port, done);
},
stop: function(done) {
server.close(done);
}
};
================================================
FILE: tests/servers/express/render.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var express = require('express');
var app = express();
app.use(miniprofiler.express());
app.set('view engine', 'pug');
app.set('views', './tests/servers/views');
app.get('/', (req, res) => {
res.render('index', { title: 'Hey', message: 'Hello there!' });
});
app.get('/inside-step', (req, res) => {
req.miniprofiler.step('Step 1', (unstep) => {
req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {
res.render('index', { title: 'Hey', message: 'Hello there!' });
unstep();
}, 50);
});
});
module.exports = app;
================================================
FILE: tests/servers/express/unauthorized.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var express = require('express');
var app = express();
var options = {
authorize: (req) => {
return false;
}
};
app.use(miniprofiler.express(options));
app.get('/', (req, res) => {
res.send(res.locals.miniprofiler.include());
});
module.exports = app;
================================================
FILE: tests/servers/express/unprofiled.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var express = require('express');
var app = express();
var options = {
enable: (req) => {
return false;
}
};
app.use(miniprofiler.express(options));
app.get('/', (req, res) => {
req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {
req.miniprofiler.step('Step 1', () => {
res.send(res.locals.miniprofiler.include());
});
}, 50);
});
module.exports = app;
================================================
FILE: tests/servers/hapi/async.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var dummyModule = require('../dummy-module');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({ port: 8083 });
server.register(miniprofiler.hapi(), (err) => {
if (err) throw err;
});
server.register(miniprofiler.hapi.for(require('../async-provider.js')(dummyModule)), (err) => {
if (err) throw err;
});
server.route({
method: 'GET',
path:'/',
handler: function(request, reply) {
dummyModule.asyncFn().then(() => {
Promise.resolve(request.query.once ? undefined : dummyModule.asyncFn())
.then(() => reply(request.app.miniprofiler.include()));
});
}
});
module.exports = server;
================================================
FILE: tests/servers/hapi/custom-config.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
const Hapi = require('hapi');
var ip = require('docker-ip');
var redis = require('redis');
var client = redis.createClient(6060, ip());
const server = new Hapi.Server();
server.connection({ port: 8083 });
miniprofiler.configure({
popupRenderPosition: 'right',
storage: new miniprofiler.storage.RedisStorage(client),
ignoredPaths: [ '/hidden' ]
});
server.register(miniprofiler.hapi(), (err) => {
if (err) throw (err);
});
server.route({
method: 'GET',
path:'/',
handler: function(request, reply) {
return reply(request.app.miniprofiler.include());
}
});
server.route({
method: 'GET',
path:'/hidden',
handler: function(request, reply) {
return reply('This won\'t be profiled.');
}
});
module.exports = server;
================================================
FILE: tests/servers/hapi/default.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({ port: 8083 });
server.register(miniprofiler.hapi(), (err) => {
if (err) throw err;
});
server.register(miniprofiler.hapi.for(require('../dummy-provider.js')()), (err) => {
if (err) throw err;
});
server.route({
method: 'GET',
path:'/',
handler: function(request, reply) {
return reply(request.app.miniprofiler.include());
}
});
server.route({
method: 'GET',
path:'/step',
handler: function(request, reply) {
request.raw.req.miniprofiler.step('Step', () => {
return reply(request.app.miniprofiler.include());
});
}
});
server.route({
method: 'GET',
path:'/step-two',
handler: function(request, reply) {
request.raw.req.miniprofiler.step('Step 1', () => {
request.raw.req.miniprofiler.step('Step 2', () => {
return reply(request.app.miniprofiler.include());
});
});
}
});
server.route({
method: 'GET',
path:'/step-parallel',
handler: function(request, reply) {
var count = 0;
var finish = () => {
if (++count == 2)
return reply(request.app.miniprofiler.include());
};
request.raw.req.miniprofiler.step('Step 1', finish);
request.raw.req.miniprofiler.step('Step 2', finish);
}
});
server.route({
method: 'GET',
path:'/js-sleep',
handler: function(request, reply) {
request.raw.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {
return reply(request.app.miniprofiler.include());
}, 50);
}
});
server.route({
method: 'GET',
path:'/js-sleep-start-stop',
handler: function(request, reply) {
var timing = request.raw.req.miniprofiler.startTimeQuery('custom', 'Sleeping...');
setTimeout(function() {
request.raw.req.miniprofiler.stopTimeQuery(timing);
return reply(request.app.miniprofiler.include());
}, 50);
}
});
module.exports = server;
================================================
FILE: tests/servers/hapi/index.js
================================================
'use strict';
var server;
module.exports = {
start: function(name, port, done) {
server = require(`./${name}.js`);
server.start(done);
},
stop: function(done) {
server.stop({ }, done);
}
};
================================================
FILE: tests/servers/hapi/render.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
const Hapi = require('hapi');
const vision = require('vision');
const server = new Hapi.Server();
server.connection({ port: 8083 });
server.register(miniprofiler.hapi(), (err) => {
if (err) throw (err);
});
server.register(vision, (err) => {
if (err) throw (err);
server.views({
engines: { pug: require('pug') },
path: './tests/servers/views'
});
miniprofiler.hapi().vision(server);
});
server.route({
method: 'GET',
path:'/',
handler: function(request, reply) {
reply.view('index', { title: 'Hey', message: 'Hello there!' });
}
});
server.route({
method: 'GET',
path:'/inside-step',
handler: function(request, reply) {
request.app.miniprofiler.step('Step 1', (unstep) => {
request.app.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {
reply.view('index', { title: 'Hey', message: 'Hello there!' });
unstep();
}, 50);
});
}
});
module.exports = server;
================================================
FILE: tests/servers/hapi/unauthorized.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({ port: 8083 });
var options = {
authorize: (req) => {
return false;
}
};
server.register(miniprofiler.hapi(options), (err) => {
if (err) throw (err);
});
server.route({
method: 'GET',
path:'/',
handler: function(request, reply) {
return reply(request.app.miniprofiler.include());
}
});
module.exports = server;
================================================
FILE: tests/servers/hapi/unprofiled.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({ port: 8083 });
var options = {
enable: (req) => {
return false;
}
};
server.register(miniprofiler.hapi(options), (err) => {
if (err) throw (err);
});
server.route({
method: 'GET',
path:'/',
handler: function(request, reply) {
request.raw.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {
request.raw.req.miniprofiler.step('Step 1', () => {
return reply(request.app.miniprofiler.include());
});
}, 50);
}
});
module.exports = server;
================================================
FILE: tests/servers/index.js
================================================
'use strict';
var request = require('request');
var frameworks = {
'koa': { 'port': 8081 },
'express': { 'port': 8082 },
'hapi': { 'port': 8083 }
};
var all = [ ];
for (let fw in frameworks) {
var server = require(`./${fw}`);
server.framework = fw;
frameworks[fw].server = server;
server.setUp = function(name, done) {
Object.keys(require.cache).forEach((key) => { delete require.cache[key]; });
frameworks[fw].server.start(name, frameworks[fw].port, done);
};
server.tearDown = function(done) {
frameworks[fw].server.stop(done);
};
server.get = (path, cb) => {
request.get(`http://localhost:${frameworks[fw].port}${path}`, (err, response, body) => {
cb(err, response, body);
});
};
server.post = (path, params, cb) => {
request.post({url: `http://localhost:${frameworks[fw].port}${path}`, form: params }, (err, response, body) => {
cb(err, response, body);
});
};
all.push(server);
}
module.exports = all;
================================================
FILE: tests/servers/koa/async.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var dummyModule = require('../dummy-module');
var koa = require('koa');
var route = require('koa-route');
var app = koa();
app.use(miniprofiler.koa());
app.use(miniprofiler.koa.for(require('../async-provider.js')(dummyModule)));
app.use(route.get('/', function *(){
yield dummyModule.asyncFn().then(() => {
return Promise.resolve(this.query.once ? undefined : dummyModule.asyncFn())
.then(() => { this.body = this.state.miniprofiler.include(); });
});
}));
module.exports = app;
================================================
FILE: tests/servers/koa/custom-config.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var koa = require('koa');
var route = require('koa-route');
var app = koa();
var ip = require('docker-ip');
var redis = require('redis');
var client = redis.createClient(6060, ip());
miniprofiler.configure({
popupRenderPosition: 'right',
storage: new miniprofiler.storage.RedisStorage(client),
ignoredPaths: [ '/hidden' ]
});
app.use(miniprofiler.koa());
app.use(route.get('/', function *(){
this.body = this.state.miniprofiler.include();
}));
app.use(route.get('/hidden', function *(){
this.body = 'This won\'t be profiled.';
}));
module.exports = app;
================================================
FILE: tests/servers/koa/default.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var koa = require('koa');
var route = require('koa-route');
var app = koa();
app.use(miniprofiler.koa());
app.use(miniprofiler.koa.for(require('../dummy-provider.js')()));
app.use(route.get('/', function *(){
this.body = this.state.miniprofiler.include();
}));
app.use(route.get('/step', function *(){
this.req.miniprofiler.step('Step', () => {
this.body = this.state.miniprofiler.include();
});
}));
app.use(route.get('/step-two', function *(){
this.req.miniprofiler.step('Step 1', () => {
this.req.miniprofiler.step('Step 2', () => {
this.body = this.state.miniprofiler.include();
});
});
}));
app.use(route.get('/step-parallel', function *(){
var count = 0;
var finish = () => {
if (++count == 2)
this.body = this.state.miniprofiler.include();
};
this.req.miniprofiler.step('Step 1', finish);
this.req.miniprofiler.step('Step 2', finish);
}));
app.use(route.get('/js-sleep', function *(){
yield new Promise((resolve, reject) => {
this.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {
this.body = this.state.miniprofiler.include();
resolve();
}, 50);
});
}));
app.use(route.get('/js-sleep-start-stop', function *(){
yield new Promise((resolve, reject) => {
var timing = this.req.miniprofiler.startTimeQuery('custom', 'Sleeping...');
setTimeout(() => {
this.req.miniprofiler.stopTimeQuery(timing);
this.body = this.state.miniprofiler.include();
resolve();
}, 50);
});
}));
module.exports = app;
================================================
FILE: tests/servers/koa/index.js
================================================
'use strict';
var server;
module.exports = {
start: function(name, port, done) {
var app = require(`./${name}.js`);
server = app.listen(port, done);
},
stop: function(done) {
server.close(done);
}
};
================================================
FILE: tests/servers/koa/render.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var koa = require('koa');
var route = require('koa-route');
var views = require('koa-views');
var app = koa();
app.use(views('./tests/servers/views', { extension: 'pug' }));
app.use(miniprofiler.koa());
app.use(route.get('/', function *(){
yield this.render('index', { title: 'Hey', message: 'Hello there!' });
}));
app.use(route.get('/inside-step', function *(){
yield new Promise((resolve, reject) => {
this.req.miniprofiler.step('Step 1', (unstep) => {
this.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {
this.render('index', { title: 'Hey', message: 'Hello there!' }).then(() => {
unstep();
resolve();
});
}, 50);
});
});
}));
module.exports = app;
================================================
FILE: tests/servers/koa/unauthorized.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var koa = require('koa');
var route = require('koa-route');
var app = koa();
var options = {
authorize: (req) => {
return false;
}
};
app.use(miniprofiler.koa(options));
app.use(route.get('/', function *(){
this.body = this.state.miniprofiler.include();
}));
module.exports = app;
================================================
FILE: tests/servers/koa/unprofiled.js
================================================
'use strict';
var miniprofiler = require('../../../lib/miniprofiler.js');
var koa = require('koa');
var route = require('koa-route');
var app = koa();
var options = {
enable: (req) => {
return false;
}
};
app.use(miniprofiler.koa(options));
app.use(route.get('/', function *(){
yield new Promise((resolve, reject) => {
this.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {
this.req.miniprofiler.step('Step 1', () => {
this.body = this.state.miniprofiler.include();
resolve();
});
}, 50);
});
}));
module.exports = app;
================================================
FILE: tests/servers/views/index.pug
================================================
html
head
title= title
body
h1= message
================================================
FILE: tests/share-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Share Tests', function() {
before(server.setUp.bind(null, 'default'));
after(server.tearDown);
var expectOkResponse = (done) => (err, response, body) => {
expect(response.statusCode).to.be.equal(200);
expect(response.headers['content-type']).to.be.equal('text/html; charset=utf-8');
done();
};
var expectNotFoundResponse = (done) => (err, response, body) => {
expect(response.statusCode).to.be.equal(404);
expect(response.headers['content-type']).to.be.equal('text/plain; charset=utf-8');
done();
};
it('[GET] Valid profiled id should render share page', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
server.get(`/mini-profiler-resources/results?id=${ids[0]}`, expectOkResponse(done));
});
});
it('[POST] Valid profiled id should render share page', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
server.post('/mini-profiler-resources/results', { id: ids[0] }, expectOkResponse(done));
});
});
it('[GET] Invalid profiled id should render 404', function(done) {
server.get('/mini-profiler-resources/results?id=123', expectNotFoundResponse(done));
});
it('[POST] Invalid profiled id should render 404', function(done) {
server.post('/mini-profiler-resources/results', { id: 123 }, expectNotFoundResponse(done));
});
});
};
================================================
FILE: tests/step-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Step Tests', function() {
before(server.setUp.bind(null, 'default'));
after(server.tearDown);
it('Index route should not profile any step', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/');
expect(result.Root.Children).to.be.empty;
done();
});
});
});
it('/step route should profile one step', function(done) {
server.get('/step', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/step');
expect(result.Root.Children).to.have.lengthOf(1);
expect(result.Root.Children[0].Name).to.equal('Step');
expect(result.Root.Children[0].Children).to.be.empty;
done();
});
});
});
it('step-two route should profile two nested step', function(done) {
server.get('/step-two', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/step-two');
expect(result.Root.Children).to.have.lengthOf(1);
expect(result.Root.Children[0].Name).to.equal('Step 1');
expect(result.Root.Children[0].Children).to.have.lengthOf(1);
expect(result.Root.Children[0].Children[0].Name).to.equal('Step 2');
expect(result.Root.Children[0].Children[0].Children).to.be.empty;
done();
});
});
});
it('/step-parallel route should profile two nested step', function(done) {
server.get('/step-parallel', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal('/step-parallel');
expect(result.Root.Children).to.have.lengthOf(2);
expect(result.Root.Children[0].Name).to.equal('Step 1');
expect(result.Root.Children[0].Children).to.be.empty;
expect(result.Root.Children[1].Name).to.equal('Step 2');
expect(result.Root.Children[1].Children).to.be.empty;
done();
});
});
});
});
};
================================================
FILE: tests/timequery-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Time Query Tests', function() {
before(server.setUp.bind(null, 'default'));
after(server.tearDown);
for(let url of ['/js-sleep', '/js-sleep-start-stop']) {
it(`Custom timed query should be profiled for url '${url}'`, function(done) {
server.get(url, (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
expect(ids).to.have.lengthOf(1);
server.post('/mini-profiler-resources/results/', { id: ids[0], popup: 1 }, (err, response, body) => {
var result = JSON.parse(body);
expect(result.Id).to.equal(ids[0]);
expect(result.Name).to.equal(url);
expect(result.DurationMilliseconds).to.be.above(40);
expect(result.Root.Children).to.be.empty;
expect(result.Root.CustomTimings).to.have.property('custom');
expect(result.Root.CustomTimings.custom).to.have.lengthOf(1);
expect(result.Root.CustomTimings.custom[0].ExecuteType).to.be.equal('custom');
expect(result.Root.CustomTimings.custom[0].CommandString).to.be.equal('Sleeping...');
expect(result.Root.CustomTimings.custom[0].DurationMilliseconds).to.be.below(result.DurationMilliseconds);
done();
});
});
});
}
});
};
================================================
FILE: tests/unauthorized-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Unauthorized Tests', function() {
before(server.setUp.bind(null, 'unauthorized'));
after(server.tearDown);
it('should return profile ID', function(done) {
server.get('/', (err, response, body) => {
expect(response.headers).to.include.keys('x-miniprofiler-ids');
expect(body).to.be.equal('');
done();
});
});
it('should not allow user to get timing information from ID', function(done) {
server.get('/', (err, response) => {
var ids = JSON.parse(response.headers['x-miniprofiler-ids']);
server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {
expect(response.statusCode).to.be.equal(401);
expect(body).to.be.equal('');
done();
});
});
});
});
};
================================================
FILE: tests/unprofiled-test.js
================================================
'use strict';
var expect = require('chai').expect;
module.exports = function(server) {
describe('Unprofiled Tests', function() {
before(server.setUp.bind(null, 'unprofiled'));
after(server.tearDown);
it('should not return profile ID', function(done) {
server.get('/', (err, response) => {
expect(response.headers).to.not.include.keys('x-miniprofiler-ids');
done();
});
});
it('should not include asset', function(done) {
server.get('/', (err, response, body) => {
expect(body).to.be.equal('');
done();
});
});
var paths = [
'/',
'/includes.css',
'/results',
'/results?id=2'
];
paths.forEach((path) => {
it(`should not respond for '${path}'`, function(done) {
server.get(`/mini-profiler-resources${path}`, (err, response, body) => {
expect(response.statusCode).to.be.equal(404);
expect(response.headers['content-type']).to.be.equal('text/plain; charset=utf-8');
expect(body).to.be.equal('MiniProfiler is disabled');
done();
});
});
});
});
};
gitextract_fz3xrl6x/
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .gitmodules
├── .npmignore
├── .travis.yml
├── README.md
├── lib/
│ ├── async-context.js
│ ├── client-parser.js
│ ├── middlewares/
│ │ ├── express.js
│ │ ├── hapi.js
│ │ └── koa.js
│ ├── miniprofiler.js
│ ├── storages/
│ │ ├── inmemory.js
│ │ └── redis.js
│ ├── ui.js
│ └── utils.js
├── package.json
└── tests/
├── assets-test.js
├── basic-test.js
├── client-test.js
├── concurrent-async-test.js
├── custom-config-test.js
├── index.js
├── render-test.js
├── servers/
│ ├── async-provider.js
│ ├── dummy-module.js
│ ├── dummy-provider.js
│ ├── express/
│ │ ├── async.js
│ │ ├── custom-config.js
│ │ ├── default.js
│ │ ├── index.js
│ │ ├── render.js
│ │ ├── unauthorized.js
│ │ └── unprofiled.js
│ ├── hapi/
│ │ ├── async.js
│ │ ├── custom-config.js
│ │ ├── default.js
│ │ ├── index.js
│ │ ├── render.js
│ │ ├── unauthorized.js
│ │ └── unprofiled.js
│ ├── index.js
│ ├── koa/
│ │ ├── async.js
│ │ ├── custom-config.js
│ │ ├── default.js
│ │ ├── index.js
│ │ ├── render.js
│ │ ├── unauthorized.js
│ │ └── unprofiled.js
│ └── views/
│ └── index.pug
├── share-test.js
├── step-test.js
├── timequery-test.js
├── unauthorized-test.js
└── unprofiled-test.js
SYMBOL INDEX (25 symbols across 4 files)
FILE: lib/async-context.js
class AsyncContext (line 5) | class AsyncContext {
method constructor (line 6) | constructor() {
method get (line 17) | get() {
method set (line 23) | set(val) {
FILE: lib/miniprofiler.js
function getPath (line 59) | function getPath(req) {
function handleRequest (line 63) | function handleRequest(enable, authorize, req, res) {
function assets (line 110) | function assets(req, res, lastPathSegment, done) {
function results (line 130) | function results(req, res, lastPathSegment, done) {
function include (line 191) | function include(id) {
function configure (line 223) | function configure(options) {
function startProfiling (line 237) | function startProfiling(request, enabled, authorized) {
function stopProfiling (line 291) | function stopProfiling(extension, request) {
function step (line 306) | function step(name, request, call) {
function timeQuery (line 343) | function timeQuery(extension, type, query, executeFunction) {
function stopTimeQuery (line 362) | function stopTimeQuery(timing) {
function startTimeQuery (line 366) | function startTimeQuery(extension, type, query) {
function unstep (line 386) | function unstep(name, request) {
function describePerformance (line 394) | function describePerformance(root, request) {
function diff (line 408) | function diff(start, stop) {
function callStack (line 417) | function callStack(stack) {
function describeTimings (line 427) | function describeTimings(timing, root) {
function describeCustomTimings (line 450) | function describeCustomTimings(customTimings, root) {
function makeStep (line 475) | function makeStep(name, time, parent) {
FILE: lib/storages/inmemory.js
function InMemoryStorage (line 6) | function InMemoryStorage(options) {
FILE: lib/storages/redis.js
function RedisStorage (line 5) | function RedisStorage(redisClient, maxAge) {
Condensed preview — 56 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (74K chars).
[
{
"path": ".eslintignore",
"chars": 14,
"preview": "ui\r\ncoverage\r\n"
},
{
"path": ".eslintrc.json",
"chars": 411,
"preview": "{\r\n \"extends\": \"eslint:recommended\",\r\n \"env\": {\r\n \"node\": true,\r\n \"es6\": true,\r\n \"mocha\": true\r\n },\r\n \"rul"
},
{
"path": ".gitignore",
"chars": 194,
"preview": "logs\r\n*.log\r\nnpm-debug.log*\r\npids\r\n*.pid\r\n*.seed\r\n*.rdb\r\n*.DS_STORE\r\nlib-cov\r\ncoverage\r\n.nyc_output\r\n.grunt\r\n.lock-wscri"
},
{
"path": ".gitmodules",
"chars": 77,
"preview": "[submodule \"ui\"]\r\n\tpath = ui\r\n\turl = https://github.com/MiniProfiler/ui.git\r\n"
},
{
"path": ".npmignore",
"chars": 52,
"preview": "coverage\r\ntests\r\nnode_modules\r\nexamples\r\n.travis.yml"
},
{
"path": ".travis.yml",
"chars": 344,
"preview": "language: node_js\r\nnode_js:\r\n - \"8\"\r\n - \"stable\"\r\n\r\nsudo: required\r\n\r\nservices:\r\n - docker\r\n\r\nbefore_script:\r\n - npm"
},
{
"path": "README.md",
"chars": 4401,
"preview": "# MiniProfiler for Node.js\r\n\r\nNode.js implementation of Stack Exchange's MiniProfiler\r\n\r\n[;\n\nclass AsyncContext {\n constructor() {\n this.map = new Map"
},
{
"path": "lib/client-parser.js",
"chars": 1818,
"preview": "'use strict';\r\n\r\n var _ = require('./utils.js');\r\n\r\nlet insertInOrder = (array, timing) => {\r\n if (timing.Start <= 0)\r\n"
},
{
"path": "lib/middlewares/express.js",
"chars": 939,
"preview": "'use strict';\r\n\r\nconst asyncContext = require('../async-context');\r\n\r\nmodule.exports = {\r\n buildMiddleware: function(pr"
},
{
"path": "lib/middlewares/hapi.js",
"chars": 1897,
"preview": "'use strict';\r\n\r\nconst asyncContext = require('../async-context');\r\n\r\nmodule.exports = {\r\n buildMiddleware: function(pr"
},
{
"path": "lib/middlewares/koa.js",
"chars": 1190,
"preview": "'use strict';\r\n\r\nconst asyncContext = require('../async-context');\r\n\r\nmodule.exports = {\r\n buildMiddleware: function(pr"
},
{
"path": "lib/miniprofiler.js",
"chars": 13543,
"preview": "'use strict';\r\n\r\n/*\r\n * MiniProfiler implementation for node.js.\r\n *\r\n * Apache License, Version 2.0\r\n *\r\n * Kevin Mo"
},
{
"path": "lib/storages/inmemory.js",
"chars": 566,
"preview": "'use strict';\r\n\r\nvar LRU = require('lru-cache');\r\nlet miniprofilerHashKey = '_miniprofiler_';\r\n\r\nfunction InMemoryStorag"
},
{
"path": "lib/storages/redis.js",
"chars": 526,
"preview": "'use strict';\r\n\r\nlet miniprofilerHashKey = '_miniprofiler_';\r\n\r\nfunction RedisStorage(redisClient, maxAge) {\r\n this.max"
},
{
"path": "lib/ui.js",
"chars": 835,
"preview": "'use strict';\r\n\r\nconst fileStore = { };\r\n\r\nconst fs = require('fs');\r\nconst path = require('path');\r\nconst _ = require('"
},
{
"path": "lib/utils.js",
"chars": 994,
"preview": "'use strict';\n\nconst isFunction = (obj) => {\n return typeof obj == 'function' || false;\n};\n\nconst tagsToReplace = {\n '"
},
{
"path": "package.json",
"chars": 1564,
"preview": "{\n \"name\": \"miniprofiler\",\n \"version\": \"2.0.0\",\n \"description\": \"A simple but effective mini-profiler.\",\n \"main\": \"l"
},
{
"path": "tests/assets-test.js",
"chars": 1118,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\nvar fs = require('fs');\r\n\r\nmodule.exports = function(server) {\r\n "
},
{
"path": "tests/basic-test.js",
"chars": 1870,
"preview": "'use strict';\n\nvar expect = require('chai').expect;\nvar pkg = require('../package.json');\n\nmodule.exports = function(ser"
},
{
"path": "tests/client-test.js",
"chars": 2173,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n describe('Client Timing "
},
{
"path": "tests/concurrent-async-test.js",
"chars": 1251,
"preview": "'use strict';\n\nvar expect = require('chai').expect;\n\nmodule.exports = function(server) {\n describe('Concurrent Async Re"
},
{
"path": "tests/custom-config-test.js",
"chars": 1958,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\nvar pkg = require('../package.json');\r\n\r\nmodule.exports = functio"
},
{
"path": "tests/index.js",
"chars": 349,
"preview": "'use strict';\r\n\r\nvar fs = require('fs');\r\nvar servers = require('./servers');\r\n\r\nvar testCases = fs.readdirSync('./tests"
},
{
"path": "tests/render-test.js",
"chars": 2051,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n\r\n describe('Render Tests"
},
{
"path": "tests/servers/async-provider.js",
"chars": 449,
"preview": "'use strict';\n\nmodule.exports = function(obj) {\n return {\n name: 'dummy-async',\n handler: function(req, res, next"
},
{
"path": "tests/servers/dummy-module.js",
"chars": 71,
"preview": "'use strict';\n\nmodule.exports = {\n\tasyncFn: () => Promise.resolve()\n};\n"
},
{
"path": "tests/servers/dummy-provider.js",
"chars": 151,
"preview": "'use strict';\r\n\r\nmodule.exports = function() {\r\n return {\r\n name: 'dummy',\r\n handler: function(req, res, next) {\r"
},
{
"path": "tests/servers/express/async.js",
"chars": 524,
"preview": "'use strict';\n\nvar miniprofiler = require('../../../lib/miniprofiler.js');\nvar dummyModule = require('../dummy-module');"
},
{
"path": "tests/servers/express/custom-config.js",
"chars": 629,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\nvar ip "
},
{
"path": "tests/servers/express/default.js",
"chars": 1396,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar a"
},
{
"path": "tests/servers/express/index.js",
"chars": 235,
"preview": "'use strict';\r\n\r\nvar server;\r\n\r\nmodule.exports = {\r\n start: function(name, port, done) {\r\n var app = require(`./${na"
},
{
"path": "tests/servers/express/render.js",
"chars": 665,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar a"
},
{
"path": "tests/servers/express/unauthorized.js",
"chars": 361,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar a"
},
{
"path": "tests/servers/express/unprofiled.js",
"chars": 506,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar a"
},
{
"path": "tests/servers/hapi/async.js",
"chars": 725,
"preview": "'use strict';\n\nvar miniprofiler = require('../../../lib/miniprofiler.js');\nvar dummyModule = require('../dummy-module');"
},
{
"path": "tests/servers/hapi/custom-config.js",
"chars": 862,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\n\r\nconst Hapi = require('hapi');\r\n\r\nvar ip "
},
{
"path": "tests/servers/hapi/default.js",
"chars": 2073,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\n\r\nconst ser"
},
{
"path": "tests/servers/hapi/index.js",
"chars": 225,
"preview": "'use strict';\r\n\r\nvar server;\r\n\r\nmodule.exports = {\r\n start: function(name, port, done) {\r\n server = require(`./${nam"
},
{
"path": "tests/servers/hapi/render.js",
"chars": 1079,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\nconst visio"
},
{
"path": "tests/servers/hapi/unauthorized.js",
"chars": 523,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\n\r\nconst ser"
},
{
"path": "tests/servers/hapi/unprofiled.js",
"chars": 696,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\n\r\nconst ser"
},
{
"path": "tests/servers/index.js",
"chars": 1027,
"preview": "'use strict';\r\n\r\nvar request = require('request');\r\nvar frameworks = {\r\n 'koa': { 'port': 8081 },\r\n 'express': { 'port"
},
{
"path": "tests/servers/koa/async.js",
"chars": 571,
"preview": "'use strict';\n\nvar miniprofiler = require('../../../lib/miniprofiler.js');\nvar dummyModule = require('../dummy-module');"
},
{
"path": "tests/servers/koa/custom-config.js",
"chars": 671,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = req"
},
{
"path": "tests/servers/koa/default.js",
"chars": 1664,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = req"
},
{
"path": "tests/servers/koa/index.js",
"chars": 235,
"preview": "'use strict';\r\n\r\nvar server;\r\n\r\nmodule.exports = {\r\n start: function(name, port, done) {\r\n var app = require(`./${na"
},
{
"path": "tests/servers/koa/render.js",
"chars": 850,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = req"
},
{
"path": "tests/servers/koa/unauthorized.js",
"chars": 392,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = req"
},
{
"path": "tests/servers/koa/unprofiled.js",
"chars": 624,
"preview": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = req"
},
{
"path": "tests/servers/views/index.pug",
"chars": 55,
"preview": "html\r\n head\r\n title= title\r\n body\r\n h1= message"
},
{
"path": "tests/share-test.js",
"chars": 1685,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n describe('Share Tests', "
},
{
"path": "tests/step-test.js",
"chars": 3335,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n describe('Step Tests', f"
},
{
"path": "tests/timequery-test.js",
"chars": 1452,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n describe('Time Query Tes"
},
{
"path": "tests/unauthorized-test.js",
"chars": 956,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n describe('Unauthorized T"
},
{
"path": "tests/unprofiled-test.js",
"chars": 1184,
"preview": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n describe('Unprofiled Tes"
}
]
About this extraction
This page contains the full source code of the MiniProfiler/node GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 56 files (65.0 KB), approximately 17.7k tokens, and a symbol index with 25 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.