diff --git a/body-parser/body-parser.d.ts b/body-parser/body-parser.d.ts new file mode 100644 index 000000000..0cd67332a --- /dev/null +++ b/body-parser/body-parser.d.ts @@ -0,0 +1,12 @@ +// Type definitions for body-parser +// Project: http://expressjs.com +// Definitions by: Santi Albo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "body-parser" { + import express = require('express'); + function e(options?: any): express.RequestHandler; + export = e; +} \ No newline at end of file diff --git a/compression/compression-tests.ts b/compression/compression-tests.ts new file mode 100644 index 000000000..ecfcab432 --- /dev/null +++ b/compression/compression-tests.ts @@ -0,0 +1,10 @@ +/// + +import express = require('express'); +import compress = require('compression'); + +var app = express(); +app.use(compress()); +app.use(compress({ + threshold: 512 +})); diff --git a/compression/compression.d.ts b/compression/compression.d.ts new file mode 100644 index 000000000..00b2e0459 --- /dev/null +++ b/compression/compression.d.ts @@ -0,0 +1,20 @@ +// Type definitions for compression +// Project: https://github.com/expressjs/compression +// Definitions by: Santi Albo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "compression" { + import express = require('express'); + + module e { + interface CompressionOptions { + threshold?: number; + filter?: Function; + } + } + + function e(options?: e.CompressionOptions): express.RequestHandler; + export = e; +} \ No newline at end of file diff --git a/cookie-parser/cookie-parser-tests.ts b/cookie-parser/cookie-parser-tests.ts new file mode 100644 index 000000000..94e8a9fdb --- /dev/null +++ b/cookie-parser/cookie-parser-tests.ts @@ -0,0 +1,7 @@ +/// + +import express = require('express'); +import cookieParser = require('cookie-parser'); + +var app = express(); +app.use(cookieParser('optional secret string')); diff --git a/cookie-parser/cookie-parser.d.ts b/cookie-parser/cookie-parser.d.ts new file mode 100644 index 000000000..a4897c5e7 --- /dev/null +++ b/cookie-parser/cookie-parser.d.ts @@ -0,0 +1,12 @@ +// Type definitions for cookie-parser +// Project: https://github.com/expressjs/cookie-parser +// Definitions by: Santi Albo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "cookie-parser" { + import express = require('express'); + function e(secret?: string, options?: any): express.RequestHandler; + export = e; +} \ No newline at end of file diff --git a/errorhandler/errorhandler-tests.ts b/errorhandler/errorhandler-tests.ts new file mode 100644 index 000000000..1d02ed14c --- /dev/null +++ b/errorhandler/errorhandler-tests.ts @@ -0,0 +1,7 @@ +/// + +import express = require('express'); +import errorhandler = require('errorhandler'); +var app = express(); + +app.use(errorhandler()); diff --git a/errorhandler/errorhandler.d.ts b/errorhandler/errorhandler.d.ts new file mode 100644 index 000000000..31bf44ce1 --- /dev/null +++ b/errorhandler/errorhandler.d.ts @@ -0,0 +1,12 @@ +// Type definitions for errorhandler +// Project: https://github.com/expressjs/errorhandler +// Definitions by: Santi Albo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "errorhandler" { + import express = require('express'); + function e(): express.ErrorRequestHandler; + export = e; +} \ No newline at end of file diff --git a/express/express-tests.ts b/express/express-tests.ts index 57d1d638c..76fa4da0d 100644 --- a/express/express-tests.ts +++ b/express/express-tests.ts @@ -3,1496 +3,34 @@ import express = require('express'); var app = express(); -////////////////////////// +app.engine('jade', require('jade').__express); +app.engine('html', require('ejs').renderFile); -var hash: any; - -// config - -app.set('view engine', 'ejs'); -app.set('views', __dirname + '/views'); - -// middleware - -app.use(express.bodyParser()); -app.use(express.cookieParser('shhhh, very secret')); -app.use(express.session()); - -// Session-persisted message middleware - -app.use((req: express.Request, res: express.Response, next) => { - var err = req.session.error - , msg = req.session.success; - delete req.session.error; - delete req.session.success; - res.locals.message = ''; - if (err) res.locals.message = '

' + err + '

'; - if (msg) res.locals.message = '

' + msg + '

'; - next(); -}); - -// dummy database - -var users = { - tj: { name: 'tj' } -}; - -// when you create a user, generate a salt -// and hash the password ('foobar' is the pass here) - -hash('foobar', (err, salt, hash) => { - if (err) throw err; - // store the salt & hash in the "db" - users.tj.salt = salt; - users.tj.hash = hash; -}); - - -// Authenticate using our plain-object database of doom! - -function authenticate(name, pass, fn) { - if (!module.parent) console.log('authenticating %s:%s', name, pass); - var user = users[name]; - // query the db for the given username - if (!user) return fn(new Error('cannot find user')); - // apply the same algorithm to the POSTed password, applying - // the hash against the pass / salt, if there is a match we - // found the user - hash(pass, user.salt, (err, hash) => { - if (err) return fn(err); - if (hash == user.hash) return fn(null, user); - fn(new Error('invalid password')); - }); -} - -function restrict(req: express.Request, res: express.Response, next?: Function) { - if (req.session.user) { - next(); - } else { - req.session.error = 'Access denied!'; - res.redirect('/login'); - } -} - -app.get('/', (req: express.Request, res: express.Response) => { - res.redirect('login'); -}); - -app.get('/restricted', restrict, (req: express.Request, res: express.Response) => { - res.send('Wahoo! restricted area, click to logout'); -}); - -app.get('/logout', (req: express.Request, res: express.Response) => { - // destroy the user's session to log them out - // will be re-created next request - req.session.destroy(() => { - res.redirect('/'); - }); -}); - -app.get('/login', (req: express.Request, res: express.Response) => { - res.render('login'); -}); - -app.post('/login', (req: express.Request, res: express.Response) => { - authenticate(req.body.username, req.body.password, (err, user) => { - if (user) { - // Regenerate session when signing in - // to prevent fixation - req.session.regenerate(() => { - // Store the user's primary key - // in the session store to be retrieved, - // or in this case the entire user object - req.session.user = user; - req.session.success = 'Authenticated as ' + user.name - + ' click to logout. ' - + ' You may now access /restricted.'; - res.redirect('back'); - }); - } else { - req.session.error = 'Authentication failed, please check your ' - + ' username and password.' - + ' (use "tj" and "foobar")'; - res.redirect('login'); - } - }); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -////////////// - -app.set('views', __dirname); -app.set('view engine', 'jade'); - -var pets = []; - -var n = 1000; -while (n--) { - pets.push({ name: 'Tobi', age: 2, species: 'ferret' }); - pets.push({ name: 'Loki', age: 1, species: 'ferret' }); - pets.push({ name: 'Jane', age: 6, species: 'ferret' }); -} - -app.use(express.logger('dev')); - -app.get('/', (req: express.Request, res: express.Response) => { - res.render('pets', { pets: pets }); -}); - -app.listen(3000); -console.log('Express listening on port 3000'); - -///////////// - -app.get('/', (req: express.Request, res: express.Response) => { - res.format({ - html: () => { - res.send('
    ' + users.map(user => { - return '
  • ' + user.name + '
  • '; - }).join('') + '
'); - }, - - text: () => { - res.send(users.map(user => { - return ' - ' + user.name + '\n'; - }).join('')); - }, - - json: () => { - res.json(users); - } - }); -}); - -// or you could write a tiny middleware like -// this to abstract make things a bit more declarative: - -function format(mod) { - var obj = require(mod); - return (req: express.Request, res: express.Response) => { - res.format(obj); - }; -} - -app.get('/users', format('./users')); - -if (!module.parent) { - app.listen(3000); - console.log('listening on port 3000'); -} - -///////////////////////// - -// add favicon() before logger() so -// GET /favicon.ico requests are not -// logged, because this middleware -// reponds to /favicon.ico and does not -// call next() -app.use(express.favicon()); - -// custom log format -if ('test' != process.env.NODE_ENV) - app.use(express.logger(':method :url')); - -// parses request cookies, populating -// req.cookies and req.signedCookies -// when the secret is passed, used -// for signing the cookies. -app.use(express.cookieParser('my secret here')); - -// parses json, x-www-form-urlencoded, and multipart/form-data -app.use(express.bodyParser()); - -app.get('/', (req: express.Request, res: express.Response) => { - if (req.cookies.remember) { - res.send('Remembered :). Click to forget!.'); - } else { - res.send('

Check to ' - + '.

'); - } -}); - -app.get('/forget', (req: express.Request, res: express.Response) => { - res.clearCookie('remember'); - res.redirect('back'); -}); - -app.post('/', (req: express.Request, res: express.Response) => { - var minute = 60000; - if (req.body.remember) res.cookie('remember', 1, { maxAge: minute }); - res.redirect('back'); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -/////////////////// - -// ignore GET /favicon.ico -app.use(express.favicon()); - -// pass a secret to cookieParser() for signed cookies -app.use(express.cookieParser('manny is cool')); - -// add req.session cookie support -app.use(express.cookieSession()); - -// do something with the session -app.use(count); - -// custom middleware -function count(req: express.Request, res: express.Response) { - req.session.count = req.session.count || 0; - var n = req.session.count++; - res.send('viewed ' + n + ' times\n'); -} - -if (!module.parent) { - app.listen(3000); - console.log('Express server listening on port 3000'); -} - -/////////////// - -var api = app; - -app.use(express.static(__dirname + '/public')); - -// api middleware - -api.use(express.logger('dev')); -api.use(express.bodyParser()); - -/** - * CORS support. - */ - -api.all('*', (req: express.Request, res: express.Response, next) => { - if (!req.get('Origin')) return next(); - // use "*" here to accept any origin - res.set('Access-Control-Allow-Origin', 'http://localhost:3000'); - res.set('Access-Control-Allow-Methods', 'GET, POST'); - res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type'); - // res.set('Access-Control-Allow-Max-Age', 3600); - if ('OPTIONS' == req.method) return res.send(200); - next(); -}); - -/** - * POST a user. - */ - -api.post('/user', (req: express.Request, res: express.Response) => { - console.log(req.body); - res.send(201); -}); - -app.listen(3000); -api.listen(3001); - -console.log('app listening on 3000'); -console.log('api listening on 3001'); - -//////////////////// - -app.get('/', (req: express.Request, res: express.Response) => { - res.send(''); -}); - -// /files/* is accessed via req.params[0] -// but here we name it :file -app.get('/files/:file(*)', (req: express.Request, res: express.Response) => { - var file = req.params.file - , path = __dirname + '/files/' + file; - - res.download(path); -}); - -// error handling middleware. Because it's -// below our routes, you will be able to -// "intercept" errors, otherwise Connect -// will respond with 500 "Internal Server Error". -app.use((err, req, res: express.Response, next) => { - // special-case 404s, - // remember you could - // render a 404 template here - if (404 == err.status) { - res.statusCode = 404; - res.send('Cant find that file, sorry!'); - } else { - next(err); - } -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -/////////////////// - -// Register ejs as .html. If we did -// not call this, we would need to -// name our views foo.ejs instead -// of foo.html. The __express method -// is simply a function that engines -// use to hook into the Express view -// system by default, so if we want -// to change "foo.ejs" to "foo.html" -// we simply pass _any_ function, in this -// case `ejs.__express`. - -app.engine('.html', require('ejs').__express); - -// Optional since express defaults to CWD/views - -app.set('views', __dirname + '/views'); - -// Without this you would need to -// supply the extension to res.render() -// ex: res.render('users.html'). -app.set('view engine', 'html'); - -app.get('/', (req: express.Request, res: express.Response) => { - res.render('users', { - users: users, - title: "EJS example", - header: "Some users" - }); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express app started on port 3000'); -} - -//////////////////// - -var test: any; - -if (!test) app.use(express.logger('dev')); -app.use(app.router); - -// the error handler is strategically -// placed *below* the app.router; if it -// were above it would not receive errors -// from app.get() etc -app.use(error); - -// error handling middleware have an arity of 4 -// instead of the typical (req: express.Request, res: express.Response, next), -// otherwise they behave exactly like regular -// middleware, you may have several of them, -// in different orders etc. - -function error(err, req, res: express.Response, next) { - // log it - if (!test) console.error(err.stack); - - // respond with 500 "Internal Server Error". - res.send(500); -} - -app.get('/', () => { - // Caught and passed down to the errorHandler middleware - throw new Error('something broke!'); -}); - -app.get('/next', (req: express.Request, res: express.Response, next) => { - // We can also pass exceptions to next() - process.nextTick(() => { - next(new Error('oh no!')); - }); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -///////////////////// - -var silent: any; - -// general config -app.set('views', __dirname + '/views'); -app.set('view engine', 'jade'); - -// our custom "verbose errors" setting -// which we can use in the templates -// via settings['verbose errors'] -app.enable('verbose errors'); - -// disable them in production -// use $ NODE_ENV=production node examples/error-pages -if ('production' == app.settings.env) { - app.disable('verbose errors'); -} - -app.use(express.favicon()); - -silent || app.use(express.logger('dev')); - -// "app.router" positions our routes -// above the middleware defined below, -// this means that Express will attempt -// to match & call routes _before_ continuing -// on, at which point we assume it's a 404 because -// no route has handled the request. - -app.use(app.router); - -// Since this is the last non-error-handling -// middleware use()d, we assume 404, as nothing else -// responded. - -// $ curl http://localhost:3000/notfound -// $ curl http://localhost:3000/notfound -H "Accept: application/json" -// $ curl http://localhost:3000/notfound -H "Accept: text/plain" - -app.use((req: express.Request, res: express.Response) => { - res.status(404); - - // respond with html page - if (req.accepts('html')) { - res.render('404', { url: req.url }); - return; - } - - // respond with json - if (req.accepts('json')) { - res.send({ error: 'Not found' }); - return; - } - - // default to plain-text. send() - res.type('txt').send('Not found'); -}); - -// error-handling middleware, take the same form -// as regular middleware, however they require an -// arity of 4, aka the signature (err, req, res: express.Response, next). -// when connect has an error, it will invoke ONLY error-handling -// middleware. - -// If we were to next() here any remaining non-error-handling -// middleware would then be executed, or if we next(err) to -// continue passing the error, only error-handling middleware -// would remain being executed, however here -// we simply respond with an error page. - -app.use((err, req, res: express.Response) => { - // we may use properties of the error object - // here and next(err) appropriately, or if - // we possibly recovered from the error, simply next(). - res.status(err.status || 500); - res.render('500', { error: err }); -}); - -// Routes - -app.get('/', (req: express.Request, res: express.Response) => { - res.render('index.jade'); -}); - -app.get('/404', (req: express.Request, res: express.Response, next) => { - // trigger a 404 since no other middleware - // will match /404 after this one, and we're not - // responding here - next(); -}); - -app.get('/403', (req: express.Request, res: express.Response, next) => { - // trigger a 403 error - var err = new Error('not allowed!'); - err.status = 403; - next(err); -}); - -app.get('/500', (req: express.Request, res: express.Response, next) => { - // trigger a generic (500) error - next(new Error('keyboard cat!')); -}); - -if (!module.parent) { - app.listen(3000); - //silent ||  console.log('Express started on port 3000'); -} - -/////////////// - -var fs: any; -var md: any; - -app.set('view engine', 'jade'); -app.set('views', __dirname + '/views'); - -function User(name) { - this.private = 'heyyyy'; - this.secret = 'something'; - this.name = name; - this.id = 123; -} - -// You'll probably want to do -// something like this so you -// dont expose "secret" data. - -User.prototype.toJSON = function () { - return { - id: this.id, - name: this.name - }; -}; - -app.use(express.logger('dev')); - -// earlier on expose an object -// that we can tack properties on. -// all res.locals props are exposed -// to the templates, so "expose" will -// be present. - -app.use((req: express.Request, res: express.Response, next) => { - res.locals.expose = {}; - // you could alias this as req or res.expose - // to make it shorter and less annoying - next(); -}); - -// pretend we loaded a user - -app.use((req: express.Request, res: express.Response, next) => { - req.user = new User('Tobi'); - next(); -}); - -app.get('/', (req: express.Request, res: express.Response) => { - res.redirect('/user'); -}); - -app.get('/user', (req: express.Request, res: express.Response) => { - // we only want to expose the user - // to the client for this route: - res.locals.expose.user = req.user; - res.render('page'); -}); - -app.listen(3000); -console.log('app listening on port 3000'); - -/////////////////////// - -app.get('/', (req: express.Request, res: express.Response) => { - res.send('Hello World'); -}); - -app.listen(3000); -console.log('Express started on port 3000'); - -//////////////////// - -// register .md as an engine in express view system - -app.engine('md', (path, options, fn) => { - fs.readFile(path, 'utf8', (err, str) => { - if (err) return fn(err); - try { - var html = md(str); - html = html.replace(/\{([^}]+)\}/g, (_, name) => { - return options[name] || ''; - }); - fn(null, html); - } catch (err) { - fn(err); - } - }); -}); - -app.set('views', __dirname + '/views'); - -// make it the default so we dont need .md -app.set('view engine', 'md'); - -app.get('/', (req: express.Request, res: express.Response) => { - res.render('index', { title: 'Markdown Example' }); -}); - -app.get('/fail', (req: express.Request, res: express.Response) => { - res.render('missing', { title: 'Markdown Example' }); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -/////////////////////// - -var mformat: any; - -// bodyParser in connect 2.x uses node-formidable to parse -// the multipart form data. -app.use(express.bodyParser()); - -app.get('/', (req: express.Request, res: express.Response) => { - res.send('
' - + '

Title:

' - + '

Image:

' - + '

' - + '
'); -}); - -app.post('/', (req: express.Request, res: express.Response) => { - // the uploaded file can be found as `req.files.image` and the - // title field as `req.body.title` - res.send(mformat('\nuploaded %s (%d Kb) to %s as %s' - , req.files.image.name - , req.files.image.size / 1024 | 0 - , req.files.image.path - , req.body.title)); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -////////////////// - - -// first: -// $ npm install redis online -// $ redis-server - -/** - * Module dependencies. - */ - -var online: any; -var db: any; - -// online - -online = online(db); - -// activity tracking, in this case using -// the UA string, you would use req.user.id etc - -app.use((req: express.Request, res: express.Response, next) => { - // fire-and-forget - online.add(req.headers['user-agent']); - next(); -}); - -/** - * List helper. - */ - -function list(ids) { - return '
    ' + ids.map(id => { - return '
  • ' + id + '
  • '; - }).join('') + '
'; -} - -/** - * GET users online. - */ - -app.get('/', (req: express.Request, res: express.Response, next) => { - online.last(5, (err, ids) => { - if (err) return next(err); - res.send('

Users online: ' + ids.length + '

' + list(ids)); - }); -}); - -app.listen(3000); -console.log('listening on port 3000'); - -/////////////////// - -// Convert :to and :from to integers - -app.param(['to', 'from'], (req: express.Request, res: express.Response, next, num, name) => { - req.params[name] = num = parseInt(num, 10); - if (isNaN(num)) { - next(new Error('failed to parseInt ' + num)); - } else { - next(); - } -}); - -// Load user by id - -app.param('user', (req: express.Request, res: express.Response, next, id) => { - if (req.user = users[id]) { - next(); - } else { - next(new Error('failed to find user')); - } -}); - -/** - * GET index. - */ - -app.get('/', (req: express.Request, res: express.Response) => { - res.send('Visit /user/0 or /users/0-2'); -}); - -/** - * GET :user. - */ - -app.get('/user/:user', (req: express.Request, res: express.Response) => { - res.send('user ' + req.user.name); -}); - -/** - * GET users :from - :to. - */ - -app.get('/users/:from-:to', (req: express.Request, res: express.Response) => { - var from = req.params.from - , to = req.params.to - , names = users.map(user => { return user.name; }); - res.send('users ' + names.slice(from, to).join(', ')); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -////////////////// - -// Ad-hoc example resource method - -app.resource = function (path, obj) { - this.get(path, obj.index); - this.get(path + '/:a..:b.:format?', (req: express.Request, res: express.Response) => { - var a = parseInt(req.params.a, 10) - , b = parseInt(req.params.b, 10) - , format = req.params.format; - obj.range(req, res, a, b, format); - }); - this.get(path + '/:id', obj.show); - this.del(path + '/:id', obj.destroy); -}; - -// Fake controller. - -var FUser = { - index: (req: express.Request, res: express.Response) => { - res.send(users); - }, - show: (req: express.Request, res: express.Response) => { - res.send(users[req.params.id] || { error: 'Cannot find user' }); - }, - destroy: (req: express.Request, res: express.Response) => { - var id = req.params.id; - var destroyed = id in users; - delete users[id]; - res.send(destroyed ? 'destroyed' : 'Cannot find user'); - }, - range: (req: express.Request, res: express.Response, a, b, format) => { - var range = users.slice(a, b + 1); - switch (format) { - case 'json': - res.send(range); - break; - case 'html': - default: - var html = '
    ' + range.map(user => { - return '
  • ' + user.name + '
  • '; - }).join('\n') + '
'; - res.send(html); - break; - } - } -}; - -// curl http://localhost:3000/users -- responds with all users -// curl http://localhost:3000/users/1 -- responds with user 1 -// curl http://localhost:3000/users/4 -- responds with error -// curl http://localhost:3000/users/1..3 -- responds with several users -// curl -X DELETE http://localhost:3000/users/1 -- deletes the user - -app.resource('/users', FUser); - -app.get('/', (req: express.Request, res: express.Response) => { - res.send([ - '

Examples:

    ' - , '
  • GET /users
  • ' - , '
  • GET /users/1
  • ' - , '
  • GET /users/3
  • ' - , '
  • GET /users/1..3
  • ' - , '
  • GET /users/1..3.json
  • ' - , '
  • DELETE /users/4
  • ' - , '
' - ].join('\n')); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express started on port 3000'); -} - -///////////////////// - - -var verbose: any; - -app.map = (a, route) => { - route = route || ''; - for (var key in a) { - switch (typeof a[key]) { - // { '/path': { ... }} - case 'object': - app.map(a[key], route + key); - break; - // get: function(){ ... } - case 'function': - if (verbose) console.log('%s %s', key, route); - app[key](route, a[key]); - break; - } - } -}; - -var users2 = { - list: (req: express.Request, res: express.Response) => { - res.send('user list'); - }, - - get: (req: express.Request, res: express.Response) => { - res.send('user ' + req.params.uid); - }, - - del: (req: express.Request, res: express.Response) => { - res.send('delete users'); - } -}; - -var pets2 = { - list: (req: express.Request, res: express.Response) => { - res.send('user ' + req.params.uid + '\'s pets'); - }, - - del: (req: express.Request, res: express.Response) => { - res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid); - } -}; - -app.map({ - '/users': { - get: users2.list, - del: users2.del, - '/:uid': { - get: users.get , - '/pets': { - get: pets2.list, - '/:pid': { - del: pets2.del - } - } - } - } -}); - -app.listen(3000); - -/////////////////////////// - -// Example requests: -// curl http://localhost:3000/user/0 -// curl http://localhost:3000/user/0/edit -// curl http://localhost:3000/user/1 -// curl http://localhost:3000/user/1/edit (unauthorized since this is not you) -// curl -X DELETE http://localhost:3000/user/0 (unauthorized since you are not an admin) - -function loadUser(req: express.Request, res: express.Response, next) { - // You would fetch your user from the db - var user = users[req.params.id]; - if (user) { - req.user = user; - next(); - } else { - next(new Error('Failed to load user ' + req.params.id)); - } -} - -function andRestrictToSelf(req: express.Request, res: express.Response, next) { - // If our authenticated user is the user we are viewing - // then everything is fine :) - if (req.authenticatedUser.id == req.user.id) { - next(); - } else { - // You may want to implement specific exceptions - // such as UnauthorizedError or similar so that you - // can handle these can be special-cased in an error handler - // (view ./examples/pages for this) - next(new Error('Unauthorized')); - } -} - -function andRestrictTo(role) { - return (req: express.Request, res: express.Response, next) => { - if (req.authenticatedUser.role == role) { - next(); - } else { - next(new Error('Unauthorized')); - } - }; -} - -// Middleware for faux authentication -// you would of course implement something real, -// but this illustrates how an authenticated user -// may interact with middleware - -app.use((req: express.Request, res: express.Response, next) => { - req.authenticatedUser = users[0]; - next(); -}); - -app.get('/', (req: express.Request, res: express.Response) => { - res.redirect('/user/0'); -}); - -app.get('/user/:id', loadUser, (req: express.Request, res: express.Response) => { - res.send('Viewing user ' + req.user.name); -}); - -app.get('/user/:id/edit', loadUser, andRestrictToSelf, (req: express.Request, res: express.Response) => { - res.send('Editing user ' + req.user.name); -}); - -app.del('/user/:id', loadUser, andRestrictTo('admin'), (req: express.Request, res: express.Response) => { - res.send('Deleted user ' + req.user.name); -}); - -app.listen(3000); -console.log('Express app started on port 3000'); - -///////////////////////// - -app.set('view engine', 'jade'); -app.set('views', __dirname); - -// populate search - -db.sadd('ferret', 'tobi'); -db.sadd('ferret', 'loki'); -db.sadd('ferret', 'jane'); -db.sadd('cat', 'manny'); -db.sadd('cat', 'luna'); - -/** - * GET the search page. - */ - -app.get('/', (req: express.Request, res: express.Response) => { - res.render('search'); -}); - -/** - * GET search for :query. - */ - -app.get('/search/:query?', (req: express.Request, res: express.Response) => { - var query = req.params.query; - db.smembers(query, (err, vals) => { - if (err) return res.send(500); - res.send(vals); - }); -}); - -/** - * GET client javascript. Here we use sendfile() - * because serving __dirname with the static() middleware - * would also mean serving our server "index.js" and the "search.jade" - * template. - */ - -app.get('/client.js', (req: express.Request, res: express.Response) => { - res.sendfile(__dirname + '/client.js'); -}); - -app.listen(3000); -console.log('app listening on port 3000'); - -/////////////////// - -app.use(express.logger('dev')); - -// Required by session() middleware -// pass the secret for signed cookies -// (required by session()) -app.use(express.cookieParser('keyboard cat')); - -// Populates req.session -app.use(express.session()); - -app.get('/', (req: express.Request, res: express.Response) => { - var body = ''; - if (req.session.views) { - ++req.session.views; - } else { - req.session.views = 1; - body += '

First time visiting? view this page in several browsers :)

'; - } - res.send(body + '

viewed ' + req.session.views + ' times.

'); -}); - -app.listen(3000); -console.log('Express app started on port 3000'); - -//////////////////////// - -// log requests -app.use(express.logger('dev')); - -// express on its own has no notion -// of a "file". The express.static() -// middleware checks for a file matching -// the `req.path` within the directory -// that you pass it. In this case "GET /js/app.js" -// will look for "./public/js/app.js". - -app.use(express.static(__dirname + '/public')); - -// if you wanted to "prefix" you may use -// the mounting feature of Connect, for example -// "GET /static/js/app.js" instead of "GET /js/app.js". -// The mount-path "/static" is simply removed before -// passing control to the express.static() middleware, -// thus it serves the file correctly by ignoring "/static" app.use('/static', express.static(__dirname + '/public')); -// if for some reason you want to serve files from -// several directories, you can use express.static() -// multiple times! Here we're passing "./public/css", -// this will allow "GET /style.css" instead of "GET /css/style.css": -app.use(express.static(__dirname + '/public/css')); - -// this examples does not have any routes, however -// you may `app.use(app.router)` before or after these -// static() middleware. If placed before them your routes -// will be matched BEFORE file serving takes place. If placed -// after as shown here then file serving is performed BEFORE -// any routes are hit: -app.use(app.router); - -app.listen(3000); -console.log('listening on port 3000'); -console.log('try:'); -console.log(' GET /hello.txt'); -console.log(' GET /js/app.js'); -console.log(' GET /css/style.css'); - -////////////////// - -/* -edit /etc/vhosts: - -127.0.0.1 foo.example.com -127.0.0.1 bar.example.com -127.0.0.1 example.com -*/ - -// Main app - -var main = express(); - -main.use(express.logger('dev')); - -main.get('/', (req: express.Request, res: express.Response) => { - res.send('Hello from main app!'); -}); - -main.get('/:sub', (req: express.Request, res: express.Response) => { - res.send('requsted ' + req.params.sub); -}); - -// Redirect app - -var redirect = express(); - -redirect.all('*', (req: express.Request, res: express.Response) => { - console.log(req.subdomains); - res.redirect('http://example.com:3000/' + req.subdomains[0]); -}); - -app.use(express.vhost('*.example.com', redirect)); -app.use(express.vhost('example.com', main)); - -app.listen(3000); -console.log('Express app started on port 3000'); - -//////////////////// - -// create an error with .status. we -// can then use the property in our -// custom error handler (Connect repects this prop as well) - -function merror(status, msg) { - var err = new Error(msg); - err.status = status; - return err; -} - -// if we wanted to supply more than JSON, we could -// use something similar to the content-negotiation -// example. - -// here we validate the API key, -// by mounting this middleware to /api -// meaning only paths prefixed with "/api" -// will cause this middleware to be invoked - -app.use('/api', (req, res: express.Response, next) => { - var key = req.query['api-key']; - - // key isnt present - if (!key) return next(merror(400, 'api key required')); - - // key is invalid - if (!~apiKeys.indexOf(key)) return next(merror(401, 'invalid api key')); - - // all good, store req.key for route access - req.key = key; +// simple logger +app.use(function(req, res, next){ + console.log('%s %s', req.method, req.url); next(); }); -// position our routes above the error handling middleware, -// and below our API middleware, since we want the API validation -// to take place BEFORE our routes -app.use(app.router); - -// middleware with an arity of 4 are considered -// error handling middleware. When you next(err) -// it will be passed through the defined middleware -// in order, but ONLY those with an arity of 4, ignoring -// regular middleware. -app.use((err, req, res: express.Response) => { - // whatever you want here, feel free to populate - // properties on `err` to treat it differently in here. - res.send(err.status || 500, { error: err.message }); +app.get('/', function(req, res){ + res.send('hello world'); }); -// our custom JSON 404 middleware. Since it's placed last -// it will be the last middleware called, if all others -// invoke next() and do not respond. -app.use((req: express.Request, res: express.Response) => { - res.send(404, { error: "Lame, can't find that" }); +var router = express.Router(); + +router.use((req, res, next) => { next(); }) +router.route('/users') + .get((req, res, next) => { + res.send(req.query['token']); + }); + +app.use((req, res, next) => { + // hacky trick, router is just a handler + router(req, res, next); }); -// map of valid api keys, typically mapped to -// account info with some sort of database like redis. -// api keys do _not_ serve as authentication, merely to -// track API usage or help prevent malicious behavior etc. +app.use(router); -var apiKeys = ['foo', 'bar', 'baz']; - -// these two objects will serve as our faux database - -var repos = [ - { name: 'express', url: 'http://github.com/visionmedia/express' } - , { name: 'stylus', url: 'http://github.com/learnboost/stylus' } - , { name: 'cluster', url: 'http://github.com/learnboost/cluster' } -]; - -var userRepos = { - tobi: [repos[0], repos[1]] - , loki: [repos[1]] - , jane: [repos[2]] -}; - -// we now can assume the api key is valid, -// and simply expose the data - -app.get('/api/users', (req: express.Request, res: express.Response) => { - res.send(users); -}); - -app.get('/api/repos', (req: express.Request, res: express.Response) => { - res.send(repos); -}); - -app.get('/api/user/:name/repos', (req: express.Request, res: express.Response, next) => { - var name = req.params.name - , user = userRepos[name]; - - if (user) res.send(user); - else next(); -}); - -if (!module.parent) { - app.listen(3000); - console.log('Express server listening on port 3000'); -} - -////// - -var router = new express.Router(); - -router.get('/', function (req, resp, next?) { - resp.send('response from router'); - resp.end(); - if (next) { - next(); - } -}); - -function test_general() { - - app.use((err, req, res: express.Response) => { - console.error(err.stack); - res.send(500, 'Something broke!'); - }); - app.use(express.bodyParser()); - app.use(express.methodOverride()); - app.use(app.router); - app.use(() => {}); - app.use(express.bodyParser()); - app.use(express.methodOverride()); - app.use(app.router); - - app.get('/', (req: express.Request, res: express.Response) => { - res.send('hello world'); - }); - - app.listen(3000); - - app.set('title', 'My Site'); - app.get('title'); - - app.enable('trust proxy'); - app.get('trust proxy'); - - app.disable('trust proxy'); - app.get('trust proxy'); - - app.enabled('trust proxy'); - - app.configure(() => { - app.set('title', 'My Application'); - }); - - app.configure('development', () => { - app.set('db uri', 'localhost/dev'); - }); - - app.configure('stage', 'production', () => {}); - - app.configure('1', '2', '3', () => {}); - - app.use((req: express.Request, res: express.Response) => { - res.send('Hello World'); - }); - - app.engine('jade', require('jade').__express); - - var User; - app.param('user', (req: express.Request, res: express.Response, next, id) => { - User.find(id, (err, user) =>{ - if (err) { - next(err); - } else if (user) { - req.user = user; - next(); - } else { - next(new Error('failed to load user')); - } - }); - }); - - app.get(/^\/commits\/(\d+)(?:\.\.(\d+))?$/, (req: express.Request, res: express.Response) => { - var from = req.params[0]; - var to = req.params[1] || 'HEAD'; - res.send('commit range ' + from + '..' + to); - }); - - app.locals.title = 'My App'; - app.locals.strftime = require('strftime'); - - var requireAuthentication; - var loadUser = () => {}; - app.all('*', requireAuthentication, loadUser); - app.all('*', loadUser); - app.all('*', loadUser, loadUser, loadUser); - - app.locals.title = 'My App'; - app.locals.strftime = require('strftime'); - app.locals({ - title: 'My App', - phone: '1-250-858-9990', - email: 'me@myapp.com' - }); - app.render('email', () => {}); - - app.render('email', { name: 'Tobi' }, () => {}); -} - -function test_request() { - var req: express.Request; - req.params.name; - req.params[0]; - req.query.q; - req.body.user.name; - app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/my/files' })); - req.param('name'); - req.route; - req.cookies.name; - req.signedCookies; - req.get('Content-Type'); - req.accepts('html'); - req.accepts(['html', 'json']); - req.is('html'); - req.ip; - req.path; - req.host; - req.fresh; - req.stale; - req.xhr; - req.protocol; - req.subdomains; - req.originalUrl; - req.acceptedLanguages; - req.acceptedCharsets; - var charset; - req.acceptsCharset(charset); - var lang; - req.acceptsLanguage(lang); - req.session = null; -} - -function test_response() { - var res: express.Response; - res.status(404).sendfile('path/to/404.png'); - res.set('Content-Type', 'text/plain'); - res.set({ - 'Content-Type': 'text/plain', - 'Content-Length': '123', - 'ETag': '12345' - }); - res.get('Content-Type'); - res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true }); - res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); - res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); - res.cookie('cart', { items: [1, 2, 3] }); - res.cookie('cart', { items: [1, 2, 3] }, { maxAge: 900000 });; - res.cookie('name', 'tobi', { signed: true }); - res.cookie('name', 'tobi', { path: '/admin' }); - res.clearCookie('name', { path: '/admin' }); - res.redirect('/foo/bar'); - res.redirect('http://example.com'); - res.redirect(301, 'http://example.com'); - res.charset = 'value'; - res.send('some html'); - res.send(new Buffer('whoop')); - res.send({ some: 'json' }); - res.send('some html'); - res.send(404, 'Sorry, we cannot find that!'); - res.send(500, { error: 'something blew up' }); - res.send(200); - res.set('Content-Type', 'text/html'); - res.send(new Buffer('some html')); - res.send('some html'); - res.send({ user: 'tobi' }); - res.send([1, 2, 3]); - res.json(null); - res.json({ user: 'tobi' }); - res.json(500, { error: 'message' }); - res.jsonp(null); - res.jsonp({ user: 'tobi' }); - res.jsonp(500, { error: 'message' }); - res.jsonp({ user: 'tobi' }); - res.type('application/json'); - - res.format({ - 'text/plain': () => { - res.send('hey'); - }, - 'text/html': () => { - res.send('hey'); - }, - 'application/json': () => { - res.send({ message: 'hey' }); - } - }); - - res.attachment(); - res.attachment('path/to/logo.png'); - app.get('/user/:uid/photos/:file', (req: express.Request, res: express.Response) => { - var uid = req.params.uid - , file = req.params.file; - - req.user.mayViewFilesFrom(uid, yes => { - if (yes) { - res.sendfile('/uploads/' + uid + '/' + file); - } else { - res.send(403, 'Sorry! you cant see that.'); - } - }); - }); - - res.download('/report-12345.pdf'); - res.download('/report-12345.pdf', 'report.pdf'); - res.download('/report-12345.pdf', 'report.pdf', err => { - if (err) { } else { } - }); - - res.links({ - next: 'http://api.example.com/users?page=2', - last: 'http://api.example.com/users?page=5' - }); - - app.use((req: express.Request, res: express.Response, next) => { - res.locals.user = req.user; - res.locals.authenticated = !req.user.anonymous; - next(); - }); - res.render('index', () => {}); - res.render('user', { name: 'Tobi' }, () => {}); - -} - -function test_middleware() { - app.use(express.basicAuth('username', 'password')); - app.use(express.basicAuth((user, pass) => { - return 'tj' == user && 'wahoo' == pass; - })); - app.use(express.bodyParser()); - app.use(express.json()); - app.use(express.urlencoded()); - app.use(express.multipart()); - app.use(express.logger()); - app.use(express.compress()); - app.use(express.methodOverride()); - app.use(express.bodyParser()); - app.use(express.cookieParser()); - app.use(express.cookieParser('some secret')); - app.use(express.cookieSession()); - app.use(express.directory('public')); - app.use(express.static('public')); - app.use(router.middleware); -} - -//////////////////// - -// make sure server can be shut down -var testShutdownServer = app.listen(0); -console.log('listening on port ' + testShutdownServer.address().port); -testShutdownServer.close(); +app.listen(3000); diff --git a/express/express.d.ts b/express/express.d.ts index 40be7e4ec..d9551e22b 100644 --- a/express/express.d.ts +++ b/express/express.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Express 3.1 +// Type definitions for Express 4.x // Project: http://expressjs.com // Definitions by: Boris Yankov // Definitions: https://github.com/borisyankov/DefinitelyTyped @@ -12,11 +12,10 @@ /// - declare module Express { // These open interfaces may be extended in an application-specific manner via declaration merging. - // See for example passport.d.ts (https://github.com/borisyankov/DefinitelyTyped/blob/master/passport/passport.d.ts) + // See for example method-override.d.ts (https://github.com/borisyankov/DefinitelyTyped/blob/master/method-override/method-override.d.ts) export interface Request { } export interface Response { } export interface Application { } @@ -26,54 +25,27 @@ declare module Express { declare module "express" { import http = require('http'); - // Merged declaration, e is both a callable function and a namespace function e(): e.Express; module e { interface IRoute { path: string; - - method: string; - - callbacks: Function[]; - - regexp: any; - - /** - * Check if this route matches `path`, if so - * populate `.params`. - */ - match(path: string): boolean; + stack: any; + all(...handler: RequestHandler[]): IRoute; + get(...handler: RequestHandler[]): IRoute; + post(...handler: RequestHandler[]): IRoute; + put(...handler: RequestHandler[]): IRoute; + delete(...handler: RequestHandler[]): IRoute; + patch(...handler: RequestHandler[]): IRoute; + options(...handler: RequestHandler[]): IRoute; } - class Route implements IRoute { - path: string; - - method: string; - - callbacks: Function[]; - - regexp: any; - match(path: string): boolean; - - /** - * Initialize `Route` with the given HTTP `method`, `path`, - * and an array of `callbacks` and `options`. - * - * Options: - * - * - `sensitive` enable case-sensitive routes - * - `strict` enable strict matching for trailing slashes - * - * @param method - * @param path - * @param callbacks - * @param options - */ - new (method: string, path: string, callbacks: Function[], options: any): Route; + interface IRouterMatcher { + (name: string, ...handlers: RequestHandler[]): T; + (name: RegExp, ...handlers: RequestHandler[]): T; } - interface IRouter { + interface IRouter extends RequestHandler { /** * Map the given param placeholder `name`(s) to the given callback(s). * @@ -103,9 +75,9 @@ declare module "express" { * @param name * @param fn */ - param(name: string, fn: Function): T; - - param(name: string[], fn: Function): T; + param(name: string, handler: RequestParamHandler): T; + param(name: string, matcher: RegExp): T; + param(name: string, mapper: (param: any) => any): T; /** * Special-cased "all" method, applying the given route `path`, @@ -114,68 +86,25 @@ declare module "express" { * @param path * @param fn */ - all(path: string, fn?: (req: Request, res: Response, next: Function) => any): T; + all: IRouterMatcher; + get: IRouterMatcher; + post: IRouterMatcher; + put: IRouterMatcher; + delete: IRouterMatcher; + patch: IRouterMatcher; + options: IRouterMatcher; - all(path: string, ...callbacks: Function[]): void; + route(path: string): IRoute; - get(name: string, ...handlers: RequestFunction[]): T; - - get(name: RegExp, ...handlers: RequestFunction[]): T; - - post(name: string, ...handlers: RequestFunction[]): T; - - post(name: RegExp, ...handlers: RequestFunction[]): T; - - put(name: string, ...handlers: RequestFunction[]): T; - - put(name: RegExp, ...handlers: RequestFunction[]): T; - - del(name: string, ...handlers: RequestFunction[]): T; - - del(name: RegExp, ...handlers: RequestFunction[]): T; - - patch(name: string, ...handlers: RequestFunction[]): T; - - patch(name: RegExp, ...handlers: RequestFunction[]): T; + use(...handler: RequestHandler[]): T; + use(handler: ErrorRequestHandler): T; + use(path: string, ...handler: RequestHandler[]): T; + use(path: string, handler: ErrorRequestHandler): T; } - export class Router implements IRouter { - new (options?: any): Router; + export function Router(options?: any): Router; - middleware (): any; - - param(name: string, fn: Function): Router; - - param(name: any[], fn: Function): Router; - - all(path: string, fn?: (req: Request, res: Response, next: Function) => any): Router; - - all(path: string, ...callbacks: Function[]): void; - - get(name: string, ...handlers: RequestFunction[]): Router; - - get(name: RegExp, ...handlers: RequestFunction[]): Router; - - post(name: string, ...handlers: RequestFunction[]): Router; - - post(name: RegExp, ...handlers: RequestFunction[]): Router; - - put(name: string, ...handlers: RequestFunction[]): Router; - - put(name: RegExp, ...handlers: RequestFunction[]): Router; - - del(name: string, ...handlers: RequestFunction[]): Router; - - del(name: RegExp, ...handlers: RequestFunction[]): Router; - - patch(name: string, ...handlers: RequestFunction[]): Router; - - patch(name: RegExp, ...handlers: RequestFunction[]): Router; - } - - interface Handler { - (req: Request, res: Response, next?: Function): void; - } + export interface Router extends IRouter {} interface CookieOptions { maxAge?: number; @@ -189,61 +118,8 @@ declare module "express" { interface Errback { (err: Error): void; } - interface Session { - /** - * Update reset `.cookie.maxAge` to prevent - * the cookie from expiring when the - * session is still active. - * - * @return {Session} for chaining - * @api public - */ - touch(): Session; - - /** - * Reset `.maxAge` to `.originalMaxAge`. - */ - resetMaxAge(): Session; - - /** - * Save the session data with optional callback `fn(err)`. - */ - save(fn: Function): Session; - - /** - * Re-loads the session data _without_ altering - * the maxAge properties. Invokes the callback `fn(err)`, - * after which time if no exception has occurred the - * `req.session` property will be a new `Session` object, - * although representing the same session. - */ - reload(fn: Function): Session; - - /** - * Destroy `this` session. - */ - destroy(fn: Function): Session; - - /** - * Regenerate this request's session. - */ - regenerate(fn: Function): Session; - - user: any; - - error: string; - - success: string; - - views: any; - - count: number; - } - interface Request extends http.ServerRequest, Express.Request { - session: Session; - /** * Return request header. * @@ -450,17 +326,6 @@ declare module "express" { */ ips: string[]; - /** - * Return basic auth credentials. - * - * Examples: - * - * // http://tobi:hello@example.com - * req.auth - * // => { username: 'tobi', password: 'hello' } - */ - auth: any; - /** * Return subdomains as an array. * @@ -509,12 +374,6 @@ declare module "express" { //cookies: { string; remember: boolean; }; cookies: any; - /** - * Used to generate an anti-CSRF token. - * Placed by the CSRF protection middleware. - */ - csrfToken(): string; - method: string; params: any; @@ -650,11 +509,8 @@ declare module "express" { * }); */ sendfile(path: string): void; - sendfile(path: string, options: any): void; - sendfile(path: string, fn: Errback): void; - sendfile(path: string, options: any, fn: Errback): void; /** @@ -668,11 +524,8 @@ declare module "express" { * This method uses `res.sendfile()`. */ download(path: string): void; - download(path: string, filename: string): void; - download(path: string, fn: Errback): void; - download(path: string, filename: string, fn: Errback): void; /** @@ -782,12 +635,10 @@ declare module "express" { * * Aliased as `res.header()`. */ - set (field: any): Response; - - set (field: string, value?: string): Response; + set(field: any): Response; + set(field: string, value?: string): Response; header(field: any): Response; - header(field: string, value?: string): Response; /** @@ -823,9 +674,7 @@ declare module "express" { * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) */ cookie(name: string, val: string, options: CookieOptions): Response; - cookie(name: string, val: any, options: CookieOptions): Response; - cookie(name: string, val: any): Response; /** @@ -875,9 +724,7 @@ declare module "express" { * res.redirect('../login'); // /blog/post/1 -> /blog/login */ redirect(url: string): void; - redirect(status: number, url: string): void; - redirect(url: string, status: number): void; /** @@ -890,9 +737,7 @@ declare module "express" { * - `cache` boolean hinting to the engine it should cache * - `filename` filename of the view being rendered */ - render(view: string, options?: Object, callback?: (err: Error, html: string) => void ): void; - render(view: string, callback?: (err: Error, html: string) => void ): void; locals: any; @@ -900,10 +745,20 @@ declare module "express" { charset: string; } - interface RequestFunction { + interface ErrorRequestHandler { + (err: any, req: Request, res: Response, next: Function): any; + } + + interface RequestHandler { (req: Request, res: Response, next: Function): any; } + interface Handler extends RequestHandler {} + + interface RequestParamHandler { + (req: Request, res: Response, next: Function, param: any): any; + } + interface Application extends IRouter, Express.Application { /** * Initialize the server. @@ -919,18 +774,6 @@ declare module "express" { */ defaultConfiguration(): void; - /** - * Proxy `connect#use()` to apply settings to - * mounted applications. - **/ - use(route: string, callback?: Function): Application; - - use(route: string, server: Application): Application; - - use(callback: Function): Application; - - use(server: Application): Application; - /** * Register the given template engine callback `fn` * as `ext`. @@ -961,10 +804,6 @@ declare module "express" { */ engine(ext: string, fn: Function): Application; - param(name: string, fn: Function): Application; - - param(name: string[], fn: Function): Application; - /** * Assign `setting` to `val`, or return `setting`'s value. * @@ -977,13 +816,12 @@ declare module "express" { * @param setting * @param val */ - set (setting: string, val: string): Application; - - get(name: string): string; - - get(name: string, ...handlers: RequestFunction[]): Application; - - get(name: RegExp, ...handlers: RequestFunction[]): Application; + set(setting: string, val: string): Application; + get: { + (name: string): string; // Getter + (name: string, ...handlers: RequestHandler[]): Application; + (name: RegExp, ...handlers: RequestHandler[]): Application; + } /** * Return the app's absolute pathname @@ -1079,18 +917,12 @@ declare module "express" { * @param env * @param fn */ - configure(env: string, fn: Function): Application; - - configure(env0: string, env1: string, fn: Function): Application; - - configure(env0: string, env1: string, env2: string, fn: Function): Application; - - configure(env0: string, env1: string, env2: string, env3: string, fn: Function): Application; - - configure(env0: string, env1: string, env2: string, env3: string, env4: string, fn: Function): Application; - configure(fn: Function): Application; - + configure(env0: string, fn: Function): Application; + configure(env0: string, env1: string, fn: Function): Application; + configure(env0: string, env1: string, env2: string, fn: Function): Application; + configure(env0: string, env1: string, env2: string, env3: string, fn: Function): Application; + configure(env0: string, env1: string, env2: string, env3: string, env4: string, fn: Function): Application; /** * Render the given view `name` name with `options` @@ -1108,7 +940,6 @@ declare module "express" { * @param fn */ render(name: string, options?: Object, callback?: (err: Error, html: string) => void): void; - render(name: string, callback: (err: Error, html: string) => void): void; @@ -1130,16 +961,12 @@ declare module "express" { * https.createServer({ ... }, app).listen(443); */ listen(port: number, hostname: string, backlog: number, callback?: Function): http.Server; - listen(port: number, hostname: string, callback?: Function): http.Server; - listen(port: number, callback?: Function): http.Server; - listen(path: string, callback?: Function): http.Server; - listen(handle: any, listeningListener?: Function): http.Server; - route: IRoute; + route(path: string): IRoute; router: string; @@ -1189,237 +1016,6 @@ declare module "express" { response: Response; } - /** - * Body parser: - * - * Parse request bodies, supports _application/json_, - * _application/x-www-form-urlencoded_, and _multipart/form-data_. - * - * This is equivalent to: - * - * app.use(connect.json()); - * app.use(connect.urlencoded()); - * app.use(connect.multipart()); - * - * Examples: - * - * connect() - * .use(connect.bodyParser()) - * .use(function(req, res) { - * res.end('viewing user ' + req.body.user.name); - * }); - * - * $ curl -d 'user[name]=tj' http://local/ - * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/ - * - * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info. - * - * @param options - */ - function bodyParser(options?: any): Handler; - - /** - * Error handler: - * - * Development error handler, providing stack traces - * and error message responses for requests accepting text, html, - * or json. - * - * Text: - * - * By default, and when _text/plain_ is accepted a simple stack trace - * or error message will be returned. - * - * JSON: - * - * When _application/json_ is accepted, connect will respond with - * an object in the form of `{ "error": error }`. - * - * HTML: - * - * When accepted connect will output a nice html stack trace. - */ - function errorHandler(opts?: any): Handler; - - /** - * Method Override: - * - * Provides faux HTTP method support. - * - * Pass an optional `key` to use when checking for - * a method override, othewise defaults to _\_method_. - * The original method is available via `req.originalMethod`. - * - * @param key - */ - function methodOverride(key?: string): Handler; - - /** - * Cookie parser: - * - * Parse _Cookie_ header and populate `req.cookies` - * with an object keyed by the cookie names. Optionally - * you may enabled signed cookie support by passing - * a `secret` string, which assigns `req.secret` so - * it may be used by other middleware. - * - * Examples: - * - * connect() - * .use(connect.cookieParser('optional secret string')) - * .use(function(req, res, next){ - * res.end(JSON.stringify(req.cookies)); - * }) - * - * @param secret - */ - function cookieParser(secret?: string): Handler; - - /** - * Session: - * - * Setup session store with the given `options`. - * - * Session data is _not_ saved in the cookie itself, however - * cookies are used, so we must use the [cookieParser()](cookieParser.html) - * middleware _before_ `session()`. - * - * Examples: - * - * connect() - * .use(connect.cookieParser()) - * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }})) - * - * Options: - * - * - `key` cookie name defaulting to `connect.sid` - * - `store` session store instance - * - `secret` session cookie is signed with this secret to prevent tampering - * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` - * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") - * - * Cookie option: - * - * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set - * so the cookie becomes a browser-session cookie. When the user closes the - * browser the cookie (and session) will be removed. - * - * ## req.session - * - * To store or access session data, simply use the request property `req.session`, - * which is (generally) serialized as JSON by the store, so nested objects - * are typically fine. For example below is a user-specific view counter: - * - * connect() - * .use(connect.favicon()) - * .use(connect.cookieParser()) - * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})) - * .use(function(req, res, next){ - * var sess = req.session; - * if (sess.views) { - * res.setHeader('Content-Type', 'text/html'); - * res.write('

views: ' + sess.views + '

'); - * res.write('

expires in: ' + (sess.cookie.maxAge / 1000) + 's

'); - * res.end(); - * sess.views++; - * } else { - * sess.views = 1; - * res.end('welcome to the session demo. refresh!'); - * } - * } - * )).listen(3000); - * - * ## Session#regenerate() - * - * To regenerate the session simply invoke the method, once complete - * a new SID and `Session` instance will be initialized at `req.session`. - * - * req.session.regenerate(function(err){ - * // will have a new session here - * }); - * - * ## Session#destroy() - * - * Destroys the session, removing `req.session`, will be re-generated next request. - * - * req.session.destroy(function(err){ - * // cannot access session here - * }); - * - * ## Session#reload() - * - * Reloads the session data. - * - * req.session.reload(function(err){ - * // session updated - * }); - * - * ## Session#save() - * - * Save the session. - * - * req.session.save(function(err){ - * // session saved - * }); - * - * ## Session#touch() - * - * Updates the `.maxAge` property. Typically this is - * not necessary to call, as the session middleware does this for you. - * - * ## Session#cookie - * - * Each session has a unique cookie object accompany it. This allows - * you to alter the session cookie per visitor. For example we can - * set `req.session.cookie.expires` to `false` to enable the cookie - * to remain for only the duration of the user-agent. - * - * ## Session#maxAge - * - * Alternatively `req.session.cookie.maxAge` will return the time - * remaining in milliseconds, which we may also re-assign a new value - * to adjust the `.expires` property appropriately. The following - * are essentially equivalent - * - * var hour = 3600000; - * req.session.cookie.expires = new Date(Date.now() + hour); - * req.session.cookie.maxAge = hour; - * - * For example when `maxAge` is set to `60000` (one minute), and 30 seconds - * has elapsed it will return `30000` until the current request has completed, - * at which time `req.session.touch()` is called to reset `req.session.maxAge` - * to its original value. - * - * req.session.cookie.maxAge; - * // => 30000 - * - * Session Store Implementation: - * - * Every session store _must_ implement the following methods - * - * - `.get(sid, callback)` - * - `.set(sid, session, callback)` - * - `.destroy(sid, callback)` - * - * Recommended methods include, but are not limited to: - * - * - `.length(callback)` - * - `.clear(callback)` - * - * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo. - * - * @param options - */ - function session(options?: any): Handler; - - /** - * Hash the given `sess` object omitting changes - * to `.cookie`. - * - * @param sess - */ - function hash(sess: string): string; - /** * Static: * @@ -1444,387 +1040,7 @@ declare module "express" { * @param root * @param options */ - function static(root: string, options?: any): Handler; - - /** - * Basic Auth: - * - * Enfore basic authentication by providing a `callback(user, pass)`, - * which must return `true` in order to gain access. Alternatively an async - * method is provided as well, invoking `callback(user, pass, callback)`. Populates - * `req.user`. The final alternative is simply passing username / password - * strings. - * - * Simple username and password - * - * connect(connect.basicAuth('username', 'password')); - * - * Callback verification - * - * connect() - * .use(connect.basicAuth(function(user, pass){ - * return 'tj' == user & 'wahoo' == pass; - * })) - * - * Async callback verification, accepting `fn(err, user)`. - * - * connect() - * .use(connect.basicAuth(function(user, pass, fn){ - * User.authenticate({ user: user, pass: pass }, fn); - * })) - * - * @param callback or username - * @param realm - */ - export function basicAuth(callback: (user: string, pass: string, fn : Function) => void, realm?: string): Handler; - - export function basicAuth(callback: (user: string, pass: string) => boolean, realm?: string): Handler; - - export function basicAuth(user: string, pass: string, realm?: string): Handler; - - /** - * Compress: - * - * Compress response data with gzip/deflate. - * - * Filter: - * - * A `filter` callback function may be passed to - * replace the default logic of: - * - * exports.filter = function(req, res){ - * return /json|text|javascript/.test(res.getHeader('Content-Type')); - * }; - * - * Options: - * - * All remaining options are passed to the gzip/deflate - * creation functions. Consult node's docs for additional details. - * - * - `chunkSize` (default: 16*1024) - * - `windowBits` - * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression - * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more - * - `strategy`: compression strategy - * - * @param options - */ - function compress(options?: any): Handler; - - /** - * Cookie Session: - * - * Cookie session middleware. - * - * var app = connect(); - * app.use(connect.cookieParser()); - * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }})); - * - * Options: - * - * - `key` cookie name defaulting to `connect.sess` - * - `secret` prevents cookie tampering - * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` - * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") - * - * Clearing sessions: - * - * To clear the session simply set its value to `null`, - * `cookieSession()` will then respond with a 1970 Set-Cookie. - * - * req.session = null; - * - * @param options - */ - function cookieSession(options?: any): Handler; - - /** - * Anti CSRF: - * - * CSRF protection middleware. - * - * This middleware adds a `req.csrfToken()` function to make a token - * which should be added to requests which mutate - * state, within a hidden form field, query-string etc. This - * token is validated against the visitor's session. - * - * The default `value` function checks `req.body` generated - * by the `bodyParser()` middleware, `req.query` generated - * by `query()`, and the "X-CSRF-Token" header field. - * - * This middleware requires session support, thus should be added - * somewhere _below_ `session()` and `cookieParser()`. - * - * Options: - * - * - `value` a function accepting the request, returning the token - * - * @param options - */ - export function csrf(options?: {value?: Function}): Handler; - - /** - * Directory: - * - * Serve directory listings with the given `root` path. - * - * Options: - * - * - `hidden` display hidden (dot) files. Defaults to false. - * - `icons` display icons. Defaults to false. - * - `filter` Apply this filter function to files. Defaults to false. - * - * @param root - * @param options - */ - function directory(root: string, options?: any): Handler; - - /** - * Favicon: - * - * By default serves the connect favicon, or the favicon - * located by the given `path`. - * - * Options: - * - * - `maxAge` cache-control max-age directive, defaulting to 1 day - * - * Examples: - * - * Serve default favicon: - * - * connect() - * .use(connect.favicon()) - * - * Serve favicon before logging for brevity: - * - * connect() - * .use(connect.favicon()) - * .use(connect.logger('dev')) - * - * Serve custom favicon: - * - * connect() - * .use(connect.favicon('public/favicon.ico)) - * - * @param path - * @param options - */ - export function favicon(path?: string, options?: any): Handler; - - /** - * JSON: - * - * Parse JSON request bodies, providing the - * parsed object as `req.body`. - * - * Options: - * - * - `strict` when `false` anything `JSON.parse()` accepts will be parsed - * - `reviver` used as the second "reviver" argument for JSON.parse - * - `limit` byte limit disabled by default - * - * @param options - */ - function json(options?: any): Handler; - - /** - * Limit: - * - * Limit request bodies to the given size in `bytes`. - * - * A string representation of the bytesize may also be passed, - * for example "5mb", "200kb", "1gb", etc. - * - * connect() - * .use(connect.limit('5.5mb')) - * .use(handleImageUpload) - */ - function limit(bytes: number): Handler; - - function limit(bytes: string): Handler; - - /** - * Logger: - * - * Log requests with the given `options` or a `format` string. - * - * Options: - * - * - `format` Format string, see below for tokens - * - `stream` Output stream, defaults to _stdout_ - * - `buffer` Buffer duration, defaults to 1000ms when _true_ - * - `immediate` Write log line on request instead of response (for response times) - * - * Tokens: - * - * - `:req[header]` ex: `:req[Accept]` - * - `:res[header]` ex: `:res[Content-Length]` - * - `:http-version` - * - `:response-time` - * - `:remote-addr` - * - `:date` - * - `:method` - * - `:url` - * - `:referrer` - * - `:user-agent` - * - `:status` - * - * Formats: - * - * Pre-defined formats that ship with connect: - * - * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"' - * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms' - * - `tiny` ':method :url :status :res[content-length] - :response-time ms' - * - `dev` concise output colored by response status for development use - * - * Examples: - * - * connect.logger() // default - * connect.logger('short') - * connect.logger('tiny') - * connect.logger({ immediate: true, format: 'dev' }) - * connect.logger(':method :url - :referrer') - * connect.logger(':req[content-type] -> :res[content-type]') - * connect.logger(function(tokens, req, res){ return 'some format string' }) - * - * Defining Tokens: - * - * To define a token, simply invoke `connect.logger.token()` with the - * name and a callback function. The value returned is then available - * as ":type" in this case. - * - * connect.logger.token('type', function(req, res){ return req.headers['content-type']; }) - * - * Defining Formats: - * - * All default formats are defined this way, however it's public API as well: - * - * connect.logger.format('name', 'string or function') - */ - function logger(options: string): Handler; - - function logger(options: Function): Handler; - - function logger(options?: any): Handler; - - /** - * Compile `fmt` into a function. - * - * @param fmt - */ - function compile(fmt: string): Handler; - - /** - * Define a token function with the given `name`, - * and callback `fn(req, res)`. - * - * @param name - * @param fn - */ - function token(name: string, fn: Function): any; - - /** - * Define a `fmt` with the given `name`. - */ - function format(name: string, str: string): any; - - function format(name: string, str: Function): any; - - /** - * Query: - * - * Automatically parse the query-string when available, - * populating the `req.query` object. - * - * Examples: - * - * connect() - * .use(connect.query()) - * .use(function(req, res){ - * res.end(JSON.stringify(req.query)); - * }); - * - * The `options` passed are provided to qs.parse function. - */ - function query(options: any): Handler; - - /** - * Reponse time: - * - * Adds the `X-Response-Time` header displaying the response - * duration in milliseconds. - */ - function responseTime(): Handler; - - /** - * Static cache: - * - * Enables a memory cache layer on top of - * the `static()` middleware, serving popular - * static files. - * - * By default a maximum of 128 objects are - * held in cache, with a max of 256k each, - * totalling ~32mb. - * - * A Least-Recently-Used (LRU) cache algo - * is implemented through the `Cache` object, - * simply rotating cache objects as they are - * hit. This means that increasingly popular - * objects maintain their positions while - * others get shoved out of the stack and - * garbage collected. - * - * Benchmarks: - * - * static(): 2700 rps - * node-static: 5300 rps - * static() + staticCache(): 7500 rps - * - * Options: - * - * - `maxObjects` max cache objects [128] - * - `maxLength` max cache object length 256kb - */ - function staticCache(options: any): Handler; - - /** - * Timeout: - * - * Times out the request in `ms`, defaulting to `5000`. The - * method `req.clearTimeout()` is added to revert this behaviour - * programmatically within your application's middleware, routes, etc. - * - * The timeout error is passed to `next()` so that you may customize - * the response behaviour. This error has the `.timeout` property as - * well as `.status == 408`. - */ - function timeout(ms: number): Handler; - - /** - * Vhost: - * - * Setup vhost for the given `hostname` and `server`. - * - * connect() - * .use(connect.vhost('foo.com', fooApp)) - * .use(connect.vhost('bar.com', barApp)) - * .use(connect.vhost('*.com', mainApp)) - * - * The `server` may be a Connect server or - * a regular Node `http.Server`. - * - * @param hostname - * @param server - */ - function vhost(hostname: string, server: any): Handler; - - function urlencoded(): any; - - function multipart(): any; - + function static(root: string, options?: any): RequestHandler; } export = e; diff --git a/method-override/method-override-tests.ts b/method-override/method-override-tests.ts new file mode 100644 index 000000000..84b4e966e --- /dev/null +++ b/method-override/method-override-tests.ts @@ -0,0 +1,15 @@ +/// + +import express = require('express'); +import methodOverride = require('method-override'); +var app = express(); + +app.use(methodOverride('X-HTTP-Method-Override')); +app.use(methodOverride((req: express.Request, res: express.Response) => { + if (req.body && typeof req.body === 'object' && '_method' in req.body) { + // look in urlencoded POST bodies and delete it + var method = req.body._method + delete req.body._method + return method + } +})); diff --git a/method-override/method-override.d.ts b/method-override/method-override.d.ts new file mode 100644 index 000000000..099b5eeb9 --- /dev/null +++ b/method-override/method-override.d.ts @@ -0,0 +1,24 @@ +// Type definitions for method-override +// Project: https://github.com/expressjs/method-override +// Definitions by: Santi Albo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module Express { + export interface Request { + originalMethod?: string; + } +} + +declare module "method-override" { + import express = require('express'); + module e { + interface MethodOverrideOptions { + methods: string[]; + } + } + function e(getter: string, options?: any): express.RequestHandler; + function e(getter: (req: express.Request, res: express.Response) => string, options?: any): express.RequestHandler; + export = e; +} \ No newline at end of file diff --git a/passport/passport.d.ts b/passport/passport.d.ts index 37d4035a0..fc3dd786f 100644 --- a/passport/passport.d.ts +++ b/passport/passport.d.ts @@ -5,6 +5,12 @@ /// +declare module Express { + export interface Request { + session?: any; + } +} + declare module 'passport' { import express = require('express');