New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

journey

Package Overview
Dependencies
Maintainers
0
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

journey - npm Package Compare versions

Comparing version 0.3.1 to 0.4.0-pre

lib/journey/errors.js

446

lib/journey.js
var path = require('path');
require.paths.unshift(path.join(__dirname, 'vendor'),
path.join(__dirname, 'journey'));
require.paths.unshift(__dirname);

@@ -14,2 +13,4 @@ var sys = require("sys"),

var errors = require('journey/errors');
// Escape RegExp characters in a string

@@ -27,58 +28,19 @@ var escapeRe = (function () {

var BadRequest = journey.BadRequest = function (msg) {
this.status = 400;
this.headers = {};
this.body = { error: msg };
};
var NotFound = journey.NotFound = function (msg) {
this.status = 404;
this.headers = {};
this.body = { error: msg };
};
var MethodNotAllowed = journey.MethodNotAllowed = function (allowed) {
this.status = 405;
this.headers = { allow: allowed };
this.body = { error: "method not allowed." };
};
var NotAcceptable = journey.NotAcceptable = function (accept) {
this.status = 406;
this.headers = {};
this.body = {
error: "cannot generate '" + accept + "' response",
only: "application/json"
};
};
var NotImplemented = journey.NotImplemented = function (msg) {
this.status = 501;
this.headers = {};
this.body = { error: msg };
};
var NotAuthorized = journey.NotAuthorized = function (msg) {
this.status = 403;
this.headers = {};
this.body = { error: msg || 'Not Authorized' };
};
journey.env = 'development';
journey.version = [0, 3, 0];
journey.version = [0, 4, 0];
journey.options = {
strict: false,
strictUrls: true
strictUrls: true,
api: 'http'
};
// Copy error objects to journey.*
for (var k in errors) { journey[k] = errors[k] }
//
// The Router
//
journey.Router = function Router(options) {
var that = this;
journey.Router = function Router(routes, options) {
var map = journey.map(this);
map.__defineGetter__('root', function () {
return this.get('/');
});
map.__defineGetter__('any', function () {
return this.route(/(.*)/);
});
this.routes = [];

@@ -90,6 +52,2 @@ this.options = mixin({}, journey.options, options || {});

}
// Call map() in the context of `this.map`, so `this`
// can be used instead of the passed argument.
routes.call(map, map);
};

@@ -99,99 +57,113 @@

journey.map = function (context) {
return {
paths: [],
required: [],
journey.Router.prototype = {
//
// Define the routing table
//
map: function (routes) {
// Calls the function in the context of this instance,
// so it can be used to define routes on `this`.
routes.call(this, this);
},
paths: [],
required: [],
filter: function (/* variable arguments */) {
var args = Array.prototype.slice.call(arguments),
map = (typeof(args[args.length - 1]) === 'function') && args.pop(),
filter = args.pop() || context.options.filter;
this.required.push(filter);
map.call(this, this);
this.required.pop();
},
get: function (pattern, opts) { return this.route('GET', pattern, opts) },
put: function (pattern, opts) { return this.route('PUT', pattern, opts) },
post: function (pattern, opts) { return this.route('POST', pattern, opts) },
del: function (pattern, opts) { return this.route('DELETE', pattern, opts) },
filter: function (/* variable arguments */) {
var args = Array.prototype.slice.call(arguments),
map = (typeof(args[args.length - 1]) === 'function') && args.pop(),
filter = args.pop() || this.options.filter;
route: function (/* variable arguments */) {
var that = this, route,
args = Array.prototype.slice.call(arguments).filter(function (a) { return a }),
// Defaults
pattern = this.paths.length ? '' : /.*/,
ignoreCase = false,
method = journey.Router.methods,
constraints = [],
extension = context.options.extension ? '(?:' + context.options.extension + ')?' : '';
this.required.push(filter);
map.call(this, this);
this.required.pop();
},
Array.prototype.push.apply(constraints, this.required);
get: function (pattern, opts) { return this.route('GET', pattern, opts) },
put: function (pattern, opts) { return this.route('PUT', pattern, opts) },
post: function (pattern, opts) { return this.route('POST', pattern, opts) },
del: function (pattern, opts) { return this.route('DELETE', pattern, opts) },
args.forEach(function (arg) {
if (journey.Router.methods.indexOf(arg) !== -1 || Array.isArray(arg)) {
method = arg;
} else if (typeof(arg) === "string" || arg.exec) {
pattern = arg;
} else {
throw new(Error)("cannot understand route.");
}
});
route: function (/* variable arguments */) {
if (arguments[0].headers) { throw new(Error)("Router#route method renamed to 'handle'") }
if (typeof(pattern) === "string") {
pattern = escapeRe(pattern);
var that = this, route,
args = Array.prototype.slice.call(arguments).filter(function (a) { return a }),
// Defaults
pattern = this.paths.length ? '' : /.*/,
ignoreCase = false,
method = journey.Router.methods.slice(0),
constraints = [],
extension = this.options.extension ? '(?:' + this.options.extension + ')?' : '';
Array.prototype.push.apply(constraints, this.required);
args.forEach(function (arg) {
if (journey.Router.methods.indexOf(arg) !== -1 || Array.isArray(arg)) {
method = arg;
} else if (typeof(arg) === "string" || arg.exec) {
pattern = arg;
} else {
// If we're in a nested path, '/i' doesn't mean much,
// as we concatinate strings and regexps.
ignoreCase = this.paths.length || pattern.ignoreCase;
pattern = pattern.source;
throw new(Error)("cannot understand route.");
}
// Trim trailing and duplicate slashes and add ^$ markers
pattern = '^' + this.paths.concat(pattern ? [pattern] : [])
.join('/')
.match(/^\^?(.*?)\$?$/)[1] // Strip ^ and $
.replace(/^(\/|\\\/)(?!$)/, '') // Strip root / if pattern != '/'
.replace(/(\/|\\\/)+/g, '/') + // Squeeze slashes
extension;
pattern += context.options.strictUrls ? '$' : '\\/?$'; // Add optional trailing slash if requested
pattern = new(RegExp)(pattern, ignoreCase ? 'i' : '');
context.routes.push(route = {
pattern: pattern,
method: method,
constraints: constraints
});
});
return {
bind: function (handler) {
route.handler = handler;
return route;
},
ensure: function (handler) {
route.constraints.push(handler);
return this;
},
filter: function (handler) {
return this.ensure(handler || context.options.filter);
}
};
},
path: function (pattern, map) {
this.paths.push(pattern.exec ? pattern.source
: escapeRe(pattern));
map.call(this, this);
this.paths.pop();
},
trail: function (from, to) {
// Logging
if (typeof(pattern) === "string") {
pattern = escapeRe(pattern);
} else {
// If we're in a nested path, '/i' doesn't mean much,
// as we concatinate strings and regexps.
ignoreCase = this.paths.length || pattern.ignoreCase;
pattern = pattern.source;
}
};
};
// Trim trailing and duplicate slashes and add ^$ markers
pattern = '^' + this.paths.concat(pattern ? [pattern] : [])
.join('/')
.match(/^\^?(.*?)\$?$/)[1] // Strip ^ and $
.replace(/^(\/|\\\/)(?!$)/, '') // Strip root / if pattern != '/'
.replace(/(\/|\\\/)+/g, '/') + // Squeeze slashes
extension;
pattern += this.options.strictUrls ? '$' : '\\/?$'; // Add optional trailing slash if requested
pattern = new(RegExp)(pattern, ignoreCase ? 'i' : '');
journey.Router.prototype = {
this.routes.push(route = {
pattern: pattern,
method: Array.isArray(method) ? method : [method],
constraints: constraints
});
return {
bind: function (handler) {
route.handler = handler;
return route;
},
ensure: function (handler) {
route.constraints.push(handler);
return this;
},
filter: function (handler) {
return this.ensure(handler || that.options.filter);
}
};
},
get root() {
return this.get('/');
},
get any() {
return this.route(/(.*)/);
},
path: function (pattern, map) {
this.paths.push(pattern.exec ? pattern.source
: escapeRe(pattern));
map.call(this, this);
this.paths.pop();
},
trail: function (from, to) {
// Logging
},
// Called when the HTTP request is 'complete'
// and ready to be processed.
route: function (request, body, callback) {
handle: function (request, body, callback) {
var promise = new(events.EventEmitter);

@@ -218,3 +190,3 @@ var request = Object.create(request);

}
outcome.headers['Content-Length'] = outcome.body.length;
outcome.headers['Content-Length'] = Buffer.byteLength(outcome.body);
} else {

@@ -227,3 +199,3 @@ delete(outcome.headers["Content-Type"]);

promise.emit("log", {
promise.emit("log", {
date: new(Date)(),

@@ -240,64 +212,64 @@ method: request.method,

constraints: [],
resolve: function (request, body, dispatcher) {
var that = this, allowedMethods = [];
var validateRoute = function (route, cb) {
// Match the pattern with the url
var match = (function (pattern) {
var path = request.url.pathname;
validateRoute: function (route, request, body, allowedMethods, cb) {
// Match the pattern with the url
var match = (function (pattern) {
var path = request.url.pathname;
if (! path) { return new(BadRequest) }
if (! path) { return new(BadRequest) }
return (path.length > 1 ? path.slice(1) : path).match(pattern);
})(route.pattern);
return (path.length > 1 ? path.slice(1) : path).match(pattern);
})(route.pattern);
//
// Return here if no match to avoid potentially expensive
// async constraint operations.
//
if (!Array.isArray(match)) {
return match === null ? cb(null, false) : cb(match);
}
//
// Run through the specified constraints,
// asynchronously making sure everything passes.
//
(function checkConstraints(constraints) {
var constraint = constraints.shift();
//
// Return here if no match to avoid potentially expensive
// async constraint operations.
//
if (!Array.isArray(match)) {
return match === null ? cb(null, false) : cb(match);
}
if (constraint) {
// If the constraint is a function then expect it to have a method signature:
// asyncConstraint(request, body, callback);
constraint(request, body, function (err) {
if (err) return cb(err);
checkConstraints(constraints);
//
// Run through the specified constraints,
// asynchronously making sure everything passes.
//
(function checkConstraints(constraints) {
var constraint = constraints.shift();
if (constraint) {
// If the constraint is a function then expect it to have a method signature:
// asyncConstraint(request, body, callback);
constraint(request, body, function (err) {
if (err) return cb(err);
checkConstraints(constraints);
});
} else {
// If there is no handler for this route, return a new NotImplemented exception
if (! ('handler' in route)) { return cb(new(journey.NotImplemented)("unbound route")) }
// Otherwise, validate the route method, and return accordingly
if ((route.method.indexOf(request.method) !== -1) || !route.method) {
return cb(null, function (res, params) {
var args = [];
args.push(res);
args.push.apply(args, match.slice(1).map(function (m) {
return /^\d+$/.test(m) ? parseInt(m) : m;
}));
args.push(params);
return route.handler.apply(this, args);
});
} else {
// If there is no handler for this route, return a new NotImplemented exception
if (! ('handler' in route)) { return cb(new(NotImplemented)("unbound route")) }
// Otherwise, validate the route method, and return accordingly
if ((Array.isArray(route.method) && route.method.indexOf(request.method) !== -1) ||
(route.method === request.method) || !route.method) {
return cb(null, function (res, params) {
var args = [];
args.push(res);
args.push.apply(args, match.slice(1).map(function (m) {
return /^\d+$/.test(m) ? parseInt(m) : m;
}));
args.push(params);
return route.handler.apply(this, args);
});
} else {
if (allowedMethods.indexOf(route.method) === -1) {
allowedMethods.push(route.method);
for (var i = 0; i < route.method.length; i++) {
if (allowedMethods.indexOf(route.method[i]) === -1) {
allowedMethods.push(route.method[i]);
}
return cb(null, false);
}
return cb(null, false);
}
})(route.constraints.slice(0));
};
}
})(route.constraints.slice(0));
},
resolve: function (request, body, dispatcher) {
var that = this, allowedMethods = [];
//

@@ -308,22 +280,14 @@ // Return the first matching route

var route = routes.shift();
if (route) {
validateRoute(route, function (err, found) {
if (err) { callback(err) }
else if (found) { callback(null, found) }
if (route) { // While there are still routes to process
that.validateRoute(route, request, body, allowedMethods, function (err, found, method) {
if (err) { dispatcher(err) }
else if (found) { dispatcher(null, found) }
else { find(routes, callback) }
});
} else { // End
callback(null, false);
}
})(this.routes.slice(0), function (err, found) {
if (err) {
dispatcher(err);
} else if (found) {
dispatcher(null, found);
} else if (allowedMethods.length) {
dispatcher(new(MethodNotAllowed)(allowedMethods.join(',')));
dispatcher(new(journey.MethodNotAllowed)(allowedMethods.join(',')));
} else {
dispatcher(null, false);
}
});
})(this.routes.slice(0));
},

@@ -350,44 +314,44 @@

var route, parser, that = this,
params = querystring.parse(request.url.query || null);
params = querystring.parse(request.url.query || null);
if (! this.verifyHeaders(request)) {
return respond(new(NotAcceptable)(request.headers.accept));
return respond(new(journey.NotAcceptable)(request.headers.accept));
}
this.resolve(request, body, function (err, resolved) {
if (err) {
if (err.status) { // If it's an HTTP Error
return respond({
headers: err.headers || {},
status: err.status,
body: JSON.stringify(err.body)
});
} else {
throw err;
if (err) {
if (err.status) { // If it's an HTTP Error
return respond({
headers: err.headers || {},
status: err.status,
body: JSON.stringify(err.body)
});
} else {
throw err;
}
}
}
route = that.draw(request, respond);
if (resolved) {
if (body) {
parser = /^application\/json/.test(
request.headers["content-type"]
) ? JSON.parse : querystring.parse;
route = that.draw(request, respond);
try {
body = parser(body);
} catch (e) {
return respond(new(BadRequest)("malformed data"));
}
if (resolved) {
if (body) {
parser = /^application\/json/.test(
request.headers["content-type"]
) ? JSON.parse : querystring.parse;
// If the body is an Array, we want to return params as an array,
// else, an object. The `mixin` function will preserve the type
// of its first parameter.
params = Array.isArray(body) ? mixin(body, params) : mixin(params, body);
}
return route.go(resolved, params);
} else {
return respond(new(NotFound)("request not found"));
}
try {
body = parser(body);
} catch (e) {
return respond(new(journey.BadRequest)("malformed data"));
}
// If the body is an Array, we want to return params as an array,
// else, an object. The `mixin` function will preserve the type
// of its first parameter.
params = Array.isArray(body) ? mixin(body, params) : mixin(params, body);
}
return route.go(resolved, params);
} else {
return respond(new(journey.NotFound)("request not found"));
}
});

@@ -399,2 +363,4 @@ },

draw: function (req, respond) {
var that = this;
return {

@@ -462,3 +428,7 @@ request: req,

try {
destination.call(this, this, params || {});
if (that.options.api === 'http') {
destination.call(this, this.request, this, params || {});
} else {
destination.call(this, this, params || {});
}
} catch (err) {

@@ -465,0 +435,0 @@ this.respond({

@@ -34,4 +34,4 @@ var url = require('url'),

var promise = new(events.EventEmitter);
var result = router.route(this.mockRequest(method, path, headers),
typeof(body) === 'object' ? JSON.stringify(body) : body);
var result = router.handle(this.mockRequest(method, path, headers),
typeof(body) === 'object' ? JSON.stringify(body) : body);

@@ -38,0 +38,0 @@ result.addListener('success', function (res) {

@@ -12,5 +12,5 @@ {

"main" : "./lib/journey",
"version" : "0.3.1",
"version" : "0.4.0-pre",
"directories" : { "test": "./test" },
"engines" : { "node": "> 0.2.6" }
}

@@ -18,7 +18,10 @@ journey

//
// Create a Router object with an associated routing table
// Create a Router
//
var router = new(journey.Router)(function (map) {
map.root.bind(function (res) { res.send("Welcome") });
map.get(/^trolls\/([0-9]+)$/).bind(function (res, id) {
var router = new(journey.Router);
// Create the routing table
router.map(function () {
this.root.bind(function (req, res) { res.send("Welcome") });
this.get(/^trolls\/([0-9]+)$/).bind(function (req, res, id) {
database('trolls').get(id, function (doc) {

@@ -28,3 +31,3 @@ res.send(200, {}, doc);

};
map.post('/trolls').bind(function (res, data) {
this.post('/trolls').bind(function (req, res, data) {
sys.puts(data.type); // "Cave-Troll"

@@ -43,3 +46,3 @@ res.send(200);

//
router.route(request, body, function (result) {
router.handle(request, body, function (result) {
response.writeHead(result.status, result.headers);

@@ -61,7 +64,12 @@ response.end(result.body);

var router = new(journey.Router)(function (map) {
// Define routes here
});
var router = new(journey.Router);
The returned object exposes a `route` method, which takes three arguments:
You define some routes, with bound functions:
router.get('/hello').bind(function (req, res) { res.send('Hi there!') });
router.put('/candles').bind(function (req, res) { ... });
*Note that you may also use the `map` function to define routes.*
The `router` object exposes a `handle` method, which takes three arguments:
an `http.ServerRequest` instance, a body, and a callback, as such:

@@ -72,3 +80,3 @@

and asynchronously calls the callback with an object containing the response
headers, status and body:
headers, status and body, on the first matching route:

@@ -86,15 +94,15 @@ { status: 200,

// HTTP methods // request
map.get('/users') // GET /users
map.post('/users') // POST /users
map.del(/^users\/(\d+)$/) // DELETE /users/45
map.put(/^users\/(\d+)$/) // PUT /users/45
// route // matching request
router.get('/users') // GET /users
router.post('/users') // POST /users
router.del(/^users\/(\d+)$/) // DELETE /users/45
router.put(/^users\/(\d+)$/) // PUT /users/45
map.route('/articles') // * /articles
map.route('POST', '/users') // POST /users
map.route(['POST', 'PUT'], '/users') // POST or PUT /users
router.route('/articles') // * /articles
router.route('POST', '/users') // POST /users
router.route(['POST', 'PUT'], '/users') // POST or PUT /users
map.root // GET /
map.any // Matches all request
map.post('/', { // Only match POST requests to /
router.root // GET /
router.any // Matches all request
router.post('/', { // Only match POST requests to /
assert: function (req) { // with data in the body.

@@ -108,3 +116,3 @@ return req.body.length > 0;

map.get('/hello').bind(function (res) {});
router.get('/hello').bind(function (req, res) {});

@@ -115,3 +123,3 @@ If there is a match, the bound function is called, and passed the `response` object,

map.get('/hello').bind(function (res) {
router.get('/hello').bind(function (req, res) {
res.send(200, {}, {hello: "world"});

@@ -140,3 +148,3 @@ });

map.get('/users').bind(function (res, params) {
router.get('/users').bind(function (req, res, params) {
params.limit; // 5

@@ -157,3 +165,3 @@ });

map.get(/^([a-z]+)\/([0-9]+)$/).bind(function (res, resource, id, params) {
router.get(/^([a-z]+)\/([0-9]+)$/).bind(function (req, res, resource, id, params) {
res; // response object

@@ -169,3 +177,3 @@ resource; // "trolls"

function (responder, [capture1, capture2, ...], data/params)
function (request, responder, [capture1, capture2, ...], data/params)

@@ -177,3 +185,3 @@ ### Paths #

map.path('/domain', function () {
router.path('/domain', function () {
this.get(); // match 'GET /domain'

@@ -188,3 +196,3 @@ this.root; // match 'GET /domain/'

})
### Filters #

@@ -195,10 +203,10 @@

function authorize (request, body, cb) {
return request.headers.authorized === true
? cb(null)
return request.headers.authorized === true
? cb(null)
: cb(new journey.NotAuthorized('Not Authorized'));
}
function authorizeAdmin (request, body, cb) {
return request.headers.admin === true
? cb(null)
return request.headers.admin === true
? cb(null)
: cb(new journey.NotAuthorized('Not Admin'));

@@ -210,13 +218,13 @@ }

#### Set a global filter
var router = new(journey.Router)(function (map) {
// Define routes here
}, { filter: authorize });
Remark: This filter will not actually be enforced until you use the APIs exposed in (2) and (3)
var router = new(journey.Router)({ filter: authorize });
*Note: This filter will not actually be enforced until you use the APIs exposed in (2) and (3)*
#### Set a scoped filter in your route function
var router = new(journey.Router)(function (map) {
map.filter(function () {
var router = new(journey.Router)({ filter: authorize });
router.map(function () {
this.filter(function () {
//

@@ -226,25 +234,27 @@ // Routes in this scope will use the 'authorize' function

});
map.filter(authorizeAdmin, function () {
this.filter(authorizeAdmin, function () {
//
// Routes in this scope will use the 'authorizeAdmin' function
//
})
}, { filter: authorize });
});
});
#### Set a filter on an individual route
var router = new(journey.Router)(function (map) {
map.get('/authorized').filter().bind(function (res, params) {
var router = new(journey.Router)({ filter: authorize });
router.map(function () {
this.get('/authorized').filter().bind(function (req, res, params) {
//
// This route will be filtered using the 'authorize' function
//
//
});
map.get('/admin').filter(authorizeAdmin).bind(function (res, params) {
this.get('/admin').filter(authorizeAdmin).bind(function (req, res, params) {
//
// This route will be filtered using the 'authorizeAdmin' function
//
//
});
}, { filter: authorize });
});

@@ -256,3 +266,3 @@ ### Accessing the request object #

map.route('/articles').bind(function (res) {
router.route('/articles').bind(function (req, res) {
this.request.method; // "POST"

@@ -259,0 +269,0 @@ res.send("Thanks for your " + this.request.method + " request.");

@@ -37,3 +37,12 @@ var sys = require('sys'),

//
var router = new(journey.Router)(function (map) {
var router = new(journey.Router)({
api: 'basic',
filter: function (request, body, cb) {
return request.headers.authorized === true
? cb(null)
: cb(new journey.NotAuthorized('Not Authorized'));
}
});
router.map(function (map) {
this.route('GET', 'picnic/fail').bind(resources.picnic.fail);

@@ -104,8 +113,2 @@

});
}, {
filter: function (request, body, cb) {
return request.headers.authorized === true
? cb(null)
: cb(new journey.NotAuthorized('Not Authorized'));
}
});

@@ -172,3 +175,3 @@

});
router.route(mock.mockRequest('GET', '/noparams', {}));
router.handle(mock.mockRequest('GET', '/noparams', {}));
return promise;

@@ -175,0 +178,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc