[
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n\n[Makefile]\nindent_style = tab\n"
  },
  {
    "path": ".eslintrc.yml",
    "content": "env:\n  mocha: true\nextends: koa\nrules:\n  no-var: 0\n  prefer-arrow-callback: 0\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiled source #\n###################\n*.com\n*.class\n*.dll\n*.exe\n*.o\n*.so\n\n# Packages #\n############\n# it's better to unpack these files and commit the raw source\n# git has its own built in compression methods\n*.7z\n*.dmg\n*.gz\n*.iso\n*.jar\n*.rar\n*.tar\n*.zip\n\n# Logs and databases #\n######################\n*.log\n*.sql\n*.sqlite\n\n# OS generated files #\n######################\n.DS_Store*\nehthumbs.db\nIcon?\nThumbs.db\n.idea\n\n# Node.js #\n###########\nlib-cov\n*.seed\n*.log\n*.csv\n*.dat\n*.out\n*.pid\n*.gz\n\npids\nlogs\nresults\n\nnode_modules\nnpm-debug.log\n\n# Components #\n##############\n\n/build\n/components\n\n# ImageMagick #\n###############\n\n*.cache\n*.mpc\n\n# Other #\n#########\ntest/*.2\ntest/*/*.2\ntest/*.mp4\ntest/images/originalSideways.jpg.2\n\n# Traceur output #\n##################\nout/*"
  },
  {
    "path": ".jshintignore",
    "content": "node_modules\n*/test.js"
  },
  {
    "path": ".travis.yml",
    "content": "node_js:\n  - stable\n  - 8\nlanguage: node_js\nscript:\n  - npm run lint\n  - npm test\n"
  },
  {
    "path": "404/app.js",
    "content": "const Koa = require('koa');\n\nconst app = module.exports = new Koa();\n\napp.use(async function pageNotFound(ctx) {\n  // we need to explicitly set 404 here\n  // so that koa doesn't assign 200 on body=\n  ctx.status = 404;\n\n  switch (ctx.accepts('html', 'json')) {\n    case 'html':\n      ctx.type = 'html';\n      ctx.body = '<p>Page Not Found</p>';\n      break;\n    case 'json':\n      ctx.body = {\n        message: 'Page Not Found'\n      };\n      break;\n    default:\n      ctx.type = 'text';\n      ctx.body = 'Page Not Found';\n  }\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "404/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('404', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('when GET /', function() {\n    it('should return the 404 page', function(done) {\n      request\n        .get('/')\n        .expect(404)\n        .expect(/Page Not Found/, done);\n    });\n  });\n});\n"
  },
  {
    "path": "Readme.md",
    "content": "# Koa Examples\n\n  A repository containing small examples to illustrate the use of Koa\n  for creating web applications and other HTTP servers.\n\n# Running tests\n\n```bash\nnpm test\nnpm run lint\n```\n\n## Included Examples\n\n - [404](404) - 404 handling\n - [base-auth](base-auth) - middleware base auth example\n - [blog](blog) - multi-route & view rendering\n - [body-parsing](body-parsing) - request body parsing\n - [compose](compose) - compose middlewares example\n - [conditional-middleware](conditional-middleware) - shows how middleware may be conditionally applied\n - [cookies](cookies) - cookie usage example\n - [csrf](csrf) - middleware csrf example\n - [errors](errors) - error handling & propagation\n - [flash-messages](flash-messages) - flash example\n - [hello-world](hello-world) - hello world application\n - [multipart](multipart) - multipart example downloading files using co-busboy\n - [negotiation](negotiation) - negotiation usage example\n - [stream-file](stream-file) - simple file streaming\n - [stream-objects](stream-objects) - objects streaming\n - [stream-server-side-events](stream-server-side-events) - server side events streaming\n - [stream-view](stream-view) - view streaming\n - [templates](templates) - simple view rendering\n - [upload](upload) - multi-file uploading\n - [vhost](vhost) - virtual host example\n\n## Example Repositories\n\n - [coko](https://github.com/bhaskarmelkani/coko) - A minimal convention over configuration framework/boilerplate for Koa 2.\n - [kails](https://github.com/embbnux/kails) - A Web App like Rails build with Koa v2, Webpack and Postgres\n - [muffin](https://github.com/muffinjs/server) - A content management system build on top of Koa v2\n - [links](https://github.com/juliangruber/links) - experimental content sharing and collaboration platform\n - [component-crawler](https://github.com/component/crawler.js) - crawl users and organizations for repositories with `component.json`s\n - [bigpipe](https://github.com/jonathanong/bigpipe-example) - Facebook's BigPipe implementation in koa and component\n - [webcam-mjpeg-stream](https://github.com/jonathanong/webcam-mjpeg-stream) - stream JPEG snapshots from your Mac\n - [cnpmjs.org](https://github.com/cnpm/cnpmjs.org) - Private npm registry and web for Enterprise, base on koa, MySQL and Simple Store Service\n - [blog-mongo](https://github.com/marcusoftnet/koablog-mongo) - the blog example from this repo, but using a MongoDb database, and tests\n - [koa-rest](https://github.com/hemanth/koa-rest) - A simple app to demo REST API\n - [koajs-rest-skeleton](https://github.com/ria-com/node-koajs-rest-skeleton) - A simple Koa REST Skeleton Application\n - [koa-bookshelf](https://github.com/Tomsqualm/koa-bookshelf) - Koa example with CRUD, using MongoDB and Heroku comptability\n - [todo](https://github.com/koajs/todo) - A todo example written in koa and [react](http://facebook.github.io/react/)\n - [koa-skeleton](https://github.com/danneu/koa-skeleton) - A simple made-to-be-forked Koa app that uses Postgres and deploys to Heroku.\n     - Live demo: <https://koa-skeleton.danneu.com>\n - [nodejs-docs-samples](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/tree/master/appengine/koa) - An example Koa app and tutorial for deploying to Google App Engine\n     - Live demo: <http://koa-demo.appspot.com/>\n - [koa-passport-mongoose-graphql](https://github.com/sibeliusseraphini/koa-passport-mongoose-graphql) - Koa 2 starterkit using mongoose, graphql setup, and authentication with passport\n - [hacknical](https://github.com/ecmadao/hacknical) - A website for github user to make a better resume, based on Koa v2, redis and mongoose.\n - [koa-vue-notes-api](https://github.com/johndatserakis/koa-vue-notes-api) - A fleshed-out SPA using Koa 2.3 on the backend and Vue 2.4 on the frontend. Includes fully featured user-authentication components, CRUD actions for the user's notes, and async/await.\n - [koa-typescript-node](https://github.com/Talento90/typescript-node) - Template for building nodejs and typescript services. Features: MySql, Migrations, Docker, Unit & Integration Tests, JWT authentication, authorization, graceful shutdown, Prettier.\n - [koa-shell](https://github.com/lifeeka/koa-shell) - Structured sample skeleton application for microservices and api development with Koa.\n\n## Boilerplates\n\n - [koa2-boilerplate](https://github.com/geekplux/koa2-boilerplate) - A minimal boilerplate of koa v2 development\n - [api-boilerplate](https://github.com/koajs/api-boilerplate) - API application boilerplate\n - [component-koa-et-al-boilerplate](https://github.com/sunewt/component-koa-et-al-boilerplate) - Server/client boilerplate with component, livereload, and more\n - [koa-typescript-starter](https://github.com/ddimaria/koa-typescript-starter) - A Koa2 starter kit using TypeScript, ES6 imports/exports, Travis, Coveralls, Jasmine, Chai, Istanbul/NYC, Lodash, Nodemon, Docker, & Swagger\n\n## Yeoman Generators\n - [koa-rest](https://github.com/PatrickWolleb/generator-koa-rest) - RESTful API scaffolder with subgenerator\n - [koa](https://github.com/peter-vilja/generator-koa) - Web Application scaffolder\n - [k](https://github.com/minghe/generator-k) -  Web Application scaffolder with Chinese README\n \n ## Articles\n\n- [Building a RESTful API with Koa and Postgres](http://mherman.org/blog/2017/08/23/building-a-restful-api-with-koa-and-postgres)\n- [User Authentication with Passport and Koa](http://mherman.org/blog/2018/01/02/user-authentication-with-passport-and-koa)\n"
  },
  {
    "path": "base-auth/app.js",
    "content": "const Koa = require('koa');\nconst auth = require('koa-basic-auth');\n\nconst app = module.exports = new Koa();\n\n// custom 401 handling\n\napp.use(async function(ctx, next) {\n  try {\n    await next();\n  } catch (err) {\n    if (err.status === 401) {\n      ctx.status = 401;\n      ctx.set('WWW-Authenticate', 'Basic');\n      ctx.body = 'cant haz that';\n    } else {\n      throw err;\n    }\n  }\n});\n\n// require auth\n\napp.use(auth({ name: 'tj', pass: 'tobi' }));\n\n// secret response\n\napp.use(async function(ctx) {\n  ctx.body = 'secret';\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "base-auth/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Koa Basic Auth', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('with no credentials', function() {\n    it('should `throw` 401', function(done) {\n      request\n        .get('/')\n        .expect(401, done);\n    });\n  });\n\n  describe('with invalid credentials', function() {\n    it('should `throw` 401', function(done) {\n      request\n        .get('/')\n        .auth('user', 'invalid password')\n        .expect(401, done);\n    });\n  });\n\n  describe('with valid credentials', function() {\n    it('should call the next middleware', function(done) {\n      request\n        .get('/')\n        .auth('tj', 'tobi')\n        .expect(200)\n        .expect('secret', done);\n    });\n  });\n});\n"
  },
  {
    "path": "blog/app.js",
    "content": "\nconst render = require('./lib/render');\nconst logger = require('koa-logger');\nconst router = require('@koa/router')();\nconst koaBody = require('koa-body');\n\nconst Koa = require('koa');\nconst app = module.exports = new Koa();\n\n// \"database\"\n\nconst posts = [];\n\n// middleware\n\napp.use(logger());\n\napp.use(render);\n\napp.use(koaBody());\n\n// route definitions\n\nrouter.get('/', list)\n  .get('/post/new', add)\n  .get('/post/:id', show)\n  .post('/post', create);\n\napp.use(router.routes());\n\n/**\n * Post listing.\n */\n\nasync function list(ctx) {\n  await ctx.render('list', { posts: posts });\n}\n\n/**\n * Show creation form.\n */\n\nasync function add(ctx) {\n  await ctx.render('new');\n}\n\n/**\n * Show post :id.\n */\n\nasync function show(ctx) {\n  const id = ctx.params.id;\n  const post = posts[id];\n  if (!post) ctx.throw(404, 'invalid post id');\n  await ctx.render('show', { post: post });\n}\n\n/**\n * Create a post.\n */\n\nasync function create(ctx) {\n  const post = ctx.request.body;\n  const id = posts.push(post) - 1;\n  post.created_at = new Date();\n  post.id = id;\n  ctx.redirect('/');\n}\n\n// listen\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "blog/lib/render.js",
    "content": "\n/**\n * Module dependencies.\n */\n\nconst views = require('koa-views');\nconst path = require('path');\n\n// setup views mapping .html\n// to the swig template engine\n\nmodule.exports = views(path.join(__dirname, '/../views'), {\n  map: { html: 'swig' }\n});\n"
  },
  {
    "path": "blog/test.js",
    "content": "require('should');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Blog', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('GET /', function() {\n    it('should see title \"Posts\"', function(done) {\n      request\n      .get('/')\n      .expect(200, function(err, res) {\n        if (err) return done(err);\n        res.should.be.html;\n        res.text.should.include('<title>Posts</title>');\n        done();\n      });\n    });\n\n    it('should see 0 post', function(done) {\n      request\n      .get('/')\n      .expect(200, function(err, res) {\n        if (err) return done(err);\n\n        res.should.be.html;\n        res.text.should.include('<p>You have <strong>0</strong> posts!</p>');\n        done();\n      });\n    });\n  });\n\n  describe('POST /post/new', function() {\n    it('should create post and redirect to /', function(done) {\n      request\n      .post('/post')\n      .send({title: 'Title', body: 'Contents'})\n      .end(function(err, res) {\n        if (err) return done(err);\n\n        res.header.location.should.be.equal('/');\n        done();\n      });\n    });\n  });\n\n  describe('GET /post/0', function() {\n    it('should see post', function(done) {\n      request\n      .get('/post/0')\n      .expect(200, function(err, res) {\n        if (err) return done(err);\n\n        res.should.be.html;\n        res.text.should.include('<h1>Title</h1>');\n        res.text.should.include('<p>Contents</p>');\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "blog/views/index.html",
    "content": "<html>\n<head>\n  <title>Blog</title>\n</head>\n<body>\n  {% for post in posts %}\n  {% endfor %}\n</body>\n</html>"
  },
  {
    "path": "blog/views/layout.html",
    "content": "<html>\n<head>\n  <title>{% block title %}Blog{% endblock %}</title>\n  <style>\n    body {\n      padding: 80px;\n      font: 16px Helvetica, Arial;\n    }\n\n    h1 {\n      font-size: 2em;\n    }\n\n    h2 {\n      font-size: 1.2em;\n    }\n\n    #posts {\n      margin: 0;\n      padding: 0;\n    }\n\n    #posts li {\n      margin: 40px 0;\n      padding: 0;\n      padding-bottom: 20px;\n      border-bottom: 1px solid #eee;\n      list-style: none;\n    }\n\n    #posts li:last-child {\n      border-bottom: none;\n    }\n\n    textarea {\n      width: 500px;\n      height: 300px;\n    }\n\n    input[type=text],\n    textarea {\n      border: 1px solid #eee;\n      border-top-color: #ddd;\n      border-left-color: #ddd;\n      border-radius: 2px;\n      padding: 15px;\n      font-size: .8em;\n    }\n\n    input[type=text] {\n      width: 500px;\n    }\n  </style>\n</head>\n<body>\n  <section id=\"content\">\n    {% block content %}\n      <p>Missing content!</p>\n    {% endblock %}\n  </section>\n</body>\n</html>"
  },
  {
    "path": "blog/views/list.html",
    "content": "{% extends 'layout.html' %}\n\n{% block title %}Posts{% endblock %}\n\n{% block content %}\n  <h1>Posts</h1>\n  <p>You have <strong>{{ posts.length }}</strong> posts!</p>\n  <p><a href=\"/post/new\">Create a Post</a></p>\n  <ul id=\"posts\">\n    {% for post in posts %}\n      <li>\n        <h2>{{ post.title }}</h2>\n        <p><a href=\"/post/{{ post.id }}\">Read post</a></p>\n      </li>\n    {% endfor %}\n  </ul>\n{% endblock %}"
  },
  {
    "path": "blog/views/new.html",
    "content": "{% extends 'layout.html' %}\n\n{% block title %}New Post{% endblock %}\n\n{% block content %}\n  <h1>New Post</h1>\n  <p>Create a new post.</p>\n  <form action=\"/post\" method=\"post\">\n    <p><input type=\"text\" placeholder=\"Title\" name=\"title\"></p>\n    <p><textarea placeholder=\"Contents\" name=\"body\"></textarea></p>\n    <p><input type=\"submit\" value=\"Create\"></p>\n  </form>\n{% endblock %}"
  },
  {
    "path": "blog/views/show.html",
    "content": "{% extends 'layout.html' %}\n\n{% block title %}{{ post.title }}{% endblock %}\n\n{% block content %}\n  <h1>{{ post.title }}</h1>\n  <p>{{ post.body }}</p>\n{% endblock %}"
  },
  {
    "path": "body-parsing/app.js",
    "content": "\nconst Koa = require('koa');\nconst koaBody = require('koa-body');\n\nconst app = module.exports = new Koa();\n\napp.use(koaBody({\n  jsonLimit: '1kb'\n}));\n\n// POST .name to /uppercase\n// co-body accepts application/json\n// and application/x-www-form-urlencoded\n\napp.use(async function(ctx) {\n  const body = ctx.request.body;\n  if (!body.name) ctx.throw(400, '.name required');\n  ctx.body = { name: body.name.toUpperCase() };\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "body-parsing/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Body Parsing', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('POST /uppercase', function() {\n    describe('with JSON', function() {\n      it('should work', function(done) {\n        request\n        .post('/uppercase')\n        .send({ name: 'tobi' })\n        .expect(200)\n        .expect({ name: 'TOBI' }, done);\n      });\n    });\n\n    describe('with urlencoded', function() {\n      it('should work', function(done) {\n        request\n        .post('/uppercase')\n        .send('name=tj')\n        .expect(200)\n        .expect({ name: 'TJ' }, done);\n      });\n    });\n\n    describe('when length > limit', function() {\n      it('should 413', function(done) {\n        request\n        .post('/json')\n        .send({ name: Array(5000).join('a') })\n        .expect(413, done);\n      });\n    });\n\n    describe('when no name is sent', function() {\n      it('should 400', function(done) {\n        request\n        .post('/uppsercase')\n        .send('age=10')\n        .expect(400, done);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "compose/app.js",
    "content": "/**\n * Each `app.use()` only accepts a single generator function.\n * If you want to combine multiple generator functions into a single one,\n * you can use `koa-compose` to do so.\n * This allows you to use `app.use()` only once.\n * Your code will end up looking something like:\n *\n *   app.use(compose([\n *     function *(){},\n *     function *(){},\n *     function *(){}\n *   ]))\n*/\n\nconst compose = require('koa-compose');\nconst Koa = require('koa');\nconst app = module.exports = new Koa();\n\n// x-response-time\n\nasync function responseTime(ctx, next) {\n  const start = new Date();\n  await next();\n  const ms = new Date() - start;\n  ctx.set('X-Response-Time', ms + 'ms');\n}\n\n// logger\n\nasync function logger(ctx, next) {\n  const start = new Date();\n  await next();\n  const ms = new Date() - start;\n  if ('test' != process.env.NODE_ENV) {\n    console.log('%s %s - %s', ctx.method, ctx.url, ms);\n  }\n}\n\n// response\n\nasync function respond(ctx, next) {\n  await next();\n  if ('/' != ctx.url) return;\n  ctx.body = 'Hello World';\n}\n\n// composed middleware\n\nconst all = compose([\n  responseTime,\n  logger,\n  respond\n]);\n\napp.use(all);\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "compose/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Compose', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('when GET /', function() {\n    it('should say \"Hello World\"', function(done) {\n      request\n      .get('/')\n      .expect(200)\n      .expect('Hello World', done);\n    });\n\n    it('should set X-Response-Time', function(done) {\n      request\n      .get('/')\n      .expect('X-Response-Time', /ms$/)\n      .expect(200, done);\n    });\n  });\n\n  describe('when not GET /', function() {\n    it('should 404', function(done) {\n      request\n      .get('/aklsjdf')\n      .expect(404, done);\n    });\n  });\n});\n"
  },
  {
    "path": "conditional-middleware/app.js",
    "content": "const logger = require('koa-logger');\nconst Koa = require('koa');\nconst app = new Koa();\n\n// passing any middleware to this middleware\n// will make it conditional, and will not be used\n// when an asset is requested, illustrating how\n// middleware may \"wrap\" other middleware.\n\nfunction ignoreAssets(mw) {\n  return async function(ctx, next) {\n    if (/(\\.js|\\.css|\\.ico)$/.test(ctx.path)) {\n      await next();\n    } else {\n      // must .call() to explicitly set the receiver\n      await mw.call(this, ctx, next);\n    }\n  };\n}\n\n// TRY:\n// $ curl http://localhost:3000/\n// $ curl http://localhost:3000/style.css\n// $ curl http://localhost:3000/some.html\n\napp.use(ignoreAssets(logger()));\n\napp.use(async function(ctx) {\n  ctx.body = 'Hello World';\n});\n\napp.listen(3000);\n"
  },
  {
    "path": "cookies/app.js",
    "content": "/**\n * This example simply sets the number of views from the same client\n * both as a cookie and as a response string.\n */\n\nconst Koa = require('koa');\nconst app = module.exports = new Koa();\n\napp.use(async function(ctx) {\n  const n = ~~ctx.cookies.get('view') + 1;\n  ctx.cookies.set('view', n);\n  ctx.body = n + ' views';\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "cookies/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Cookies Views', function() {\n  after(function() {\n    server.close();\n  });\n\n  [1, 2, 3].forEach(function(i) {\n    describe('on iteration #' + i, function() {\n      it('should set the views as a cookie and as the body', function(done) {\n        request\n        .get('/')\n        .expect(200)\n        .expect('Set-Cookie', new RegExp('view=' + i))\n        .expect(i + ' views', done);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "csrf/app.js",
    "content": "const Koa = require('koa');\nconst koaBody = require('koa-body');\nconst session = require('koa-session');\nconst CSRF = require('koa-csrf');\nconst router = require('@koa/router')();\n\nconst app = module.exports = new Koa();\n\n/**\n * csrf need session\n */\n\napp.keys = ['session key', 'csrf example'];\napp.use(session(app));\napp.use(koaBody());\n\n/**\n * maybe a bodyparser\n */\n\n/**\n * csrf middleware\n */\n\napp.use(new CSRF());\n\n/**\n * route\n */\n\nrouter.get('/token', token)\n  .post('/post', post);\n\napp.use(router.routes());\n\nasync function token(ctx) {\n  ctx.body = ctx.csrf;\n}\n\nasync function post(ctx) {\n  ctx.body = {ok: true};\n}\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "csrf/test.js",
    "content": "require('should');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\nlet token;\nlet cookie;\n\ndescribe('csrf', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('GET /token', function() {\n    it('should get token', function(done) {\n      request\n      .get('/token')\n      .expect(200)\n      .end(function(err, res) {\n        token = res.text;\n        token.should.be.String;\n        cookie = res.headers['set-cookie'].join(';');\n        done(err);\n      });\n    });\n  });\n\n  describe('POST /post', function() {\n    it('should 403 without token', function(done) {\n      request\n      .post('/post')\n      .send({foo: 'bar'})\n      .expect(403, done);\n    });\n\n    it('should 403 with wrong token', function(done) {\n      request\n      .post('/post')\n      .send({foo: 'bar'})\n      .set('x-csrf-token', 'wrong token')\n      .expect(403, done);\n    });\n\n    it('should 200 with token in head', function(done) {\n      request\n      .post('/post')\n      .set('Cookie', cookie)\n      .set('x-csrf-token', token)\n      .send({foo: 'bar'})\n      .expect(200, done);\n    });\n\n    it('should 200 with token in body', function(done) {\n      request\n      .post('/post')\n      .set('Cookie', cookie)\n      .send({_csrf: token})\n      .expect(200, done);\n    });\n  });\n});\n"
  },
  {
    "path": "errors/app.js",
    "content": "const Koa = require('koa');\nconst app = module.exports = new Koa();\n\n// look ma, error propagation!\n\napp.use(async function(ctx, next) {\n  try {\n    await next();\n  } catch (err) {\n    // some errors will have .status\n    // however this is not a guarantee\n    ctx.status = err.status || 500;\n    ctx.type = 'html';\n    ctx.body = '<p>Something <em>exploded</em>, please contact Maru.</p>';\n\n    // since we handled this manually we'll\n    // want to delegate to the regular app\n    // level error handling as well so that\n    // centralized still functions correctly.\n    ctx.app.emit('error', err, ctx);\n  }\n});\n\n// response\n\napp.use(async function() {\n  throw new Error('boom boom');\n});\n\n// error handler\n\napp.on('error', function(err) {\n  if (process.env.NODE_ENV != 'test') {\n    console.log('sent error %s to the cloud', err.message);\n    console.log(err);\n  }\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "errors/test.js",
    "content": "require('should');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Errors', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('should catch the error', function(done) {\n    request\n    .get('/')\n    .expect(500)\n    .expect('Content-Type', /text\\/html/, done);\n  });\n\n  it('should emit the error on app', function(done) {\n    app.once('error', function(err, ctx) {\n      err.message.should.equal('boom boom');\n      ctx.should.be.ok;\n      done();\n    });\n\n    request\n    .get('/')\n    .end(function() {});\n  });\n});\n"
  },
  {
    "path": "flash-messages/app.js",
    "content": "/**\n * A very simple flash example.\n * Only uses JSON for simplicity.\n */\n\nconst Koa = require('koa');\nconst rawBody = require('raw-body');\nconst session = require('koa-session');\n\nconst app = module.exports = new Koa();\n\n// required for signed cookie sessions\napp.keys = ['key1', 'key2'];\napp.use(session(app));\n\napp.use(async function(ctx, next) {\n  if (ctx.method !== 'GET' || ctx.path !== '/messages') return await next();\n\n  // get any messages saved in the session\n  const messages = ctx.session.messages || [];\n  ctx.body = messages;\n\n  // delete the messages as they've been deliverd\n  delete ctx.session.messages;\n});\n\napp.use(async function(ctx, next) {\n  if (ctx.method !== 'POST' || ctx.path !== '/messages') return await next();\n\n  // the request string is the flash message\n  const message = await rawBody(ctx.req, {\n    encoding: 'utf8'\n  });\n\n  // push the message to the session\n  ctx.session.messages = ctx.session.messages || [];\n  ctx.session.messages.push(message);\n\n  // tell the client everything went okay\n  ctx.status = 204;\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "flash-messages/test.js",
    "content": "require('should');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Flash Messages', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('GET should return an empty array', function(done) {\n    request\n    .get('/messages')\n    .expect(200)\n    .expect('content-type', 'application/json; charset=utf-8')\n    .expect('[]', done);\n  });\n\n  it('POST should return 204', function(done) {\n    request\n    .post('/messages')\n    .send('hello')\n    .expect(204, done);\n  });\n\n  it('GET should return the message', function(done) {\n    request\n    .get('/messages')\n    .expect(200)\n    .expect('content-type', 'application/json; charset=utf-8')\n    .expect('[\"hello\"]', done);\n  });\n\n  it('GET should return no more messages', function(done) {\n    request\n    .get('/messages')\n    .expect(200)\n    .expect('content-type', 'application/json; charset=utf-8')\n    .expect('[]', done);\n  });\n});\n"
  },
  {
    "path": "hello-world/app.js",
    "content": "const Koa = require('koa');\nconst app = module.exports = new Koa();\n\napp.use(async function(ctx) {\n  ctx.body = 'Hello World';\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "hello-world/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Hello World', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('should say \"Hello World\"', function(done) {\n    request\n    .get('/')\n    .expect(200)\n    .expect('Hello World', done);\n  });\n});\n"
  },
  {
    "path": "multipart/app.js",
    "content": "/**\n * Multipart example downloading all the files to disk using co-busboy.\n * If all you want is to download the files to a temporary folder,\n * just use https://github.com/cojs/multipart instead of copying this code\n * as it handles file descriptor limits whereas this does not.\n */\n\nconst os = require('os');\nconst path = require('path');\nconst Koa = require('koa');\nconst fs = require('fs-promise');\nconst koaBody = require('koa-body');\n\nconst app = module.exports = new Koa();\n\napp.use(koaBody({ multipart: true }));\n\napp.use(async function(ctx) {\n  // create a temporary folder to store files\n  const tmpdir = path.join(os.tmpdir(), uid());\n\n  // make the temporary directory\n  await fs.mkdir(tmpdir);\n  const filePaths = [];\n  const files = ctx.request.files || {};\n\n  for (let key in files) {\n    const file = files[key];\n    const filePath = path.join(tmpdir, file.name);\n    const reader = fs.createReadStream(file.path);\n    const writer = fs.createWriteStream(filePath);\n    reader.pipe(writer);\n    filePaths.push(filePath);\n  }\n\n  ctx.body = filePaths;\n});\n\nif (!module.parent) app.listen(3000);\n\nfunction uid() {\n  return Math.random().toString(36).slice(2);\n}\n"
  },
  {
    "path": "multipart/test.js",
    "content": "require('should');\nconst fs = require('fs');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\n// https://github.com/mscdex/busboy/blob/master/test/test-types-multipart.js\nconst ct = 'multipart/form-data; boundary=---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k';\nconst body = [\n  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',\n  'Content-Disposition: form-data; name=\"file_name_0\"',\n  '',\n  'super alpha file',\n  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',\n  'Content-Disposition: form-data; name=\"file_name_1\"',\n  '',\n  'super beta file',\n  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',\n  'Content-Disposition: form-data; name=\"upload_file_0\"; filename=\"1k_a.dat\"',\n  'Content-Type: application/octet-stream',\n  '',\n  'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',\n  'Content-Disposition: form-data; name=\"upload_file_1\"; filename=\"1k_b.dat\"',\n  'Content-Type: application/octet-stream',\n  '',\n  'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',\n  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'\n].join('\\r\\n');\n\ndescribe('Multipart Files', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('should store all the files', function(done) {\n    request\n    .post('/')\n    .set('Content-Type', ct)\n    .send(body)\n    .expect(200)\n    .end(function(err, res) {\n      if (err) return done(err);\n\n      const files = res.body;\n      files.should.have.length(2);\n      fs.stat(files[0], function(err) {\n        if (err) return done(err);\n\n        fs.stat(files[1], done);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "negotiation/app.js",
    "content": "\nconst Koa = require('koa');\nconst app = module.exports = new Koa();\n\nconst tobi = {\n  _id: '123',\n  name: 'tobi',\n  species: 'ferret'\n};\n\nconst loki = {\n  _id: '321',\n  name: 'loki',\n  species: 'ferret'\n};\n\nconst users = {\n  tobi: tobi,\n  loki: loki\n};\n\n// content negotiation middleware.\n// note that you should always check for\n// presence of a body, and sometimes you\n// may want to check the type, as it may\n// be a stream, buffer, string, etc.\n\napp.use(async function(ctx, next) {\n  await next();\n\n  // no body? nothing to format, early return\n  if (!ctx.body) return;\n\n  // Check which type is best match by giving\n  // a list of acceptable types to `req.accepts()`.\n  const type = ctx.accepts('json', 'html', 'xml', 'text');\n\n  // not acceptable\n  if (type === false) ctx.throw(406);\n\n  // accepts json, koa handles this for us,\n  // so just return\n  if (type === 'json') return;\n\n  // accepts xml\n  if (type === 'xml') {\n    ctx.type = 'xml';\n    ctx.body = '<name>' + ctx.body.name + '</name>';\n    return;\n  }\n\n  // accepts html\n  if (type === 'html') {\n    ctx.type = 'html';\n    ctx.body = '<h1>' + ctx.body.name + '</h1>';\n    return;\n  }\n\n  // default to text\n  ctx.type = 'text';\n  ctx.body = ctx.body.name;\n});\n\n// filter responses, in this case remove ._id\n// since it's private\n\napp.use(async function(ctx, next) {\n  await next();\n\n  if (!ctx.body) return;\n\n  delete ctx.body._id;\n});\n\n// try $ GET /tobi\n// try $ GET /loki\n\napp.use(async function(ctx) {\n  const name = ctx.path.slice(1);\n  const user = users[name];\n  ctx.body = user;\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "negotiation/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('negotiation', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('json', function() {\n    it('should respond with json', function(done) {\n      request\n      .get('/tobi')\n      .set('Accept', 'application/json')\n      .expect(200)\n      .expect('Content-Type', /json/)\n      .expect({ name: 'tobi', species: 'ferret' }, done);\n    });\n  });\n\n  describe('xml', function() {\n    it('should respond with xml', function(done) {\n      request\n      .get('/tobi')\n      .set('Accept', 'application/xml')\n      .expect(200)\n      .expect('Content-Type', /xml/)\n      .expect('<name>tobi</name>', done);\n    });\n  });\n\n  describe('html', function() {\n    it('should respond with html', function(done) {\n      request\n      .get('/tobi')\n      .set('Accept', 'text/html')\n      .expect(200)\n      .expect('Content-Type', /html/)\n      .expect('<h1>tobi</h1>', done);\n    });\n  });\n\n  describe('text', function() {\n    it('should respond with html', function(done) {\n      request\n      .get('/tobi')\n      .set('Accept', 'text/plain')\n      .expect(200)\n      .expect('Content-Type', /plain/)\n      .expect('tobi', done);\n    });\n  });\n\n  describe('*/*', function() {\n    it('should give precedence to the first accepted type', function(done) {\n      request\n      .get('/tobi')\n      .set('Accept', '*/*')\n      .expect(200)\n      .expect('Content-Type', /json/)\n      .expect('{\"name\":\"tobi\",\"species\":\"ferret\"}', done);\n    });\n  });\n});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"koa-examples\",\n  \"description\": \"Examples using Koa\",\n  \"version\": \"0.0.1\",\n  \"repository\": \"https://github.com/koajs/examples\",\n  \"bugs\": \"https://github.com/koajs/examples/issues\",\n  \"dependencies\": {\n    \"ejs\": \"^2.5.6\",\n    \"fs-promise\": \"^2.0.3\",\n    \"koa\": \"^2.2.0\",\n    \"koa-basic-auth\": \"^2.0.0\",\n    \"koa-body\": \"^4.0.8\",\n    \"koa-compose\": \"^4.0.0\",\n    \"koa-csrf\": \"^3.0.6\",\n    \"koa-logger\": \"^3.0.0\",\n    \"@koa/router\": \"^8.0.5\",\n    \"koa-session\": \"^5.0.0\",\n    \"koa-static\": \"^3.0.0\",\n    \"koa-views\": \"^6.0.2\",\n    \"streaming-json-stringify\": \"^3.1.0\",\n    \"swig-templates\": \"^2.0.3\"\n  },\n  \"devDependencies\": {\n    \"eslint\": \"^3.8.1\",\n    \"eslint-config-koa\": \"^2.0.2\",\n    \"eslint-config-standard\": \"^6.2.0\",\n    \"eslint-plugin-promise\": \"^3.3.0\",\n    \"eslint-plugin-standard\": \"^2.0.1\",\n    \"mocha\": \"^5.0.0\",\n    \"should\": \"^3.3.2\",\n    \"supertest\": \"^3.0.0\"\n  },\n  \"scripts\": {\n    \"test\": \"NODE_ENV=test mocha --harmony --reporter spec --require should */test.js\",\n    \"lint\": \"eslint .\"\n  },\n  \"engines\": {\n    \"node\": \">= 7.6\"\n  },\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "stream-file/README.md",
    "content": "# stream-file\n\nStream a file from the local directory. To invoke, the following command begins listening on localhost:3000. \n\n    node --harmony app.js\n\nTo see results:\n\n    http://localhost:3000/README.md  or\n    http://localhost:3000/other-file-in-the-directory\n\n## Interesting points\n\n1. The stat() function at the bottom of app.js returns another function that will call the normal fs.stat() to get information about the named file. (The function stat() is a promise - it will ultimately return a value, although it may take a while.)\n2. When any program *yields* to a function, it pauses while that function proceeds asynchronously, and eventually returns a value. When the function returns, the program resumes at that point. \n3. In the example, app.use() starts everything off with `fstat = yield stat(fpath)`. We say it \"yields to the stat() function.\" That is, app.use() pauses while the stat() function begins to execute (asynchronously), and the node interpreter goes off to work on other tasks. When the fs.stat() call completes and returns a value, app.use() resumes, and sets the value of `fstat` to the value returned by stat().  \n4. This example also uses the createReadStream() function to create a stream which is another way to handle data (asynchronously) from a file. \n5. `this.body` gets the result of the fs.createReadStream() (which is the stream's data) and sends it to the web browser client that has connected in to the URL above.  \n"
  },
  {
    "path": "stream-file/app.js",
    "content": "const Koa = require('koa');\nconst fs = require('fs');\nconst app = module.exports = new Koa();\nconst path = require('path');\nconst extname = path.extname;\n\n// try GET /app.js\n\napp.use(async function(ctx) {\n  const fpath = path.join(__dirname, ctx.path);\n  const fstat = await stat(fpath);\n\n  if (fstat.isFile()) {\n    ctx.type = extname(fpath);\n    ctx.body = fs.createReadStream(fpath);\n  }\n});\n\nif (!module.parent) app.listen(3000);\n\n/**\n * thunkify stat\n */\n\nfunction stat(file) {\n  return new Promise(function(resolve, reject) {\n    fs.stat(file, function(err, stat) {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(stat);\n      }\n    });\n  });\n}\n"
  },
  {
    "path": "stream-file/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Stream File', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('GET /app.js', function(done) {\n    request\n    .get('/app.js')\n    .expect('content-type', /application\\/javascript/)\n    .expect(200, done);\n  });\n\n  it('GET /test.js', function(done) {\n    request\n    .get('/test.js')\n    .expect('content-type', /application\\/javascript/)\n    .expect(200, done);\n  });\n\n  it('GET /alksjdf.js', function(done) {\n    request\n    .get('/lajksdf.js')\n    .expect(404, done);\n  });\n\n  it('GET /', function(done) {\n    request\n    .get('/')\n    .expect(404, done);\n  });\n});\n"
  },
  {
    "path": "stream-objects/README.md",
    "content": "# stream-objects\n\nStream a out Javascript objects. To invoke, the following command begins listening on localhost:3000.\n\n    node --harmony app.js\n\nTo see results:\n\n    http://localhost:3000\n\n## Interesting points\n\n1. In app.js, the setImmediate() function writes out a JS object { id: 1 } to the stream, then declares another setImmediate function.\n2. The second setImmediate() function writes a second JS object { id: 2 } to the stream, then declares a third setImmediate() function.\n3. The final setImmediate() calls stream.end() to indicate that there is no more data.\n4. Note that the setImmediate() calls do **not** happen at the same moment. The first setImmediate() call is executed sometime after the initial request arrived. That setImmediate() call then declares the second setImmediate() call, which happens at least one tick later, and the third setImmediate() call happens in a separate tick.\n4. The resulting web page shows an array containing both the JS objects, in the order they were initiated, like this:\n\n    [\n{\"id\":1}\n,\n{\"id\":2}\n]\n"
  },
  {
    "path": "stream-objects/app.js",
    "content": "\nconst Koa = require('koa');\nconst JSONStream = require('streaming-json-stringify');\n\nconst app = module.exports = new Koa();\n\napp.use(async function(ctx) {\n  ctx.type = 'json';\n  const stream = ctx.body = JSONStream();\n\n  stream.on('error', ctx.onerror);\n\n  setImmediate(function() {\n    stream.write({\n      id: 1\n    });\n\n    setImmediate(function() {\n      stream.write({\n        id: 2\n      });\n\n      setImmediate(function() {\n        stream.end();\n      });\n    });\n  });\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "stream-objects/test.js",
    "content": "require('should');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Stream Objects', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('GET /', function(done) {\n    request\n    .get('/app.js')\n    .expect(200, function(err, res) {\n      if (err) return done(err);\n\n      res.body.should.eql([{\n        id: 1\n      }, {\n        id: 2\n      }]);\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "stream-server-side-events/README.md",
    "content": "# stream-server-side-events\n\nThis program continually sends events to the web browser. It simulates a series of log file entries that have been appended to a file.\n\nTo invoke, the following command begins listening on localhost:3000.\n\n    node --harmony app.js\n\nTo see results:\n\n    http://localhost:3000\n\n## Interesting points\n\n1.\n"
  },
  {
    "path": "stream-server-side-events/app.js",
    "content": "const Koa = require('koa');\nconst app = module.exports = new Koa();\n\nconst sse = require('./sse');\nconst db = require('./db');\n\napp.use(async function(ctx) {\n  // otherwise node will automatically close this connection in 2 minutes\n  ctx.req.setTimeout(Number.MAX_VALUE);\n\n  ctx.type = 'text/event-stream; charset=utf-8';\n  ctx.set('Cache-Control', 'no-cache');\n  ctx.set('Connection', 'keep-alive');\n\n  const body = ctx.body = sse();\n  const stream = db.subscribe('some event');\n  stream.pipe(body);\n\n  // if the connection closes or errors,\n  // we stop the SSE.\n  const socket = ctx.socket;\n  socket.on('error', close);\n  socket.on('close', close);\n\n  function close() {\n    stream.unpipe(body);\n    socket.removeListener('error', close);\n    socket.removeListener('close', close);\n  }\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "stream-server-side-events/db.js",
    "content": "var Readable = require('stream').Readable;\nvar inherits = require('util').inherits;\n\n/**\n * Returns a new subscription event event.\n * Real APIs would care about the `event`.\n */\n\nexports.subscribe = function(event, options) {\n  return Subscription(options);\n};\n\n/**\n * Subscription stream. Just increments the result.\n * Never ends!\n */\n\ninherits(Subscription, Readable);\n\nfunction Subscription(options) {\n  if (!(this instanceof Subscription)) return new Subscription(options);\n\n  options = options || {};\n  Readable.call(this, options);\n\n  this.value = 0;\n}\n\nSubscription.prototype._read = function() {\n  while (this.push(String(this.value++))) {}\n};\n"
  },
  {
    "path": "stream-server-side-events/sse.js",
    "content": "/**\n * Create a transform stream that converts a stream\n * to valid `data: <value>\\n\\n' events for SSE.\n */\n\nvar Transform = require('stream').Transform;\nvar inherits = require('util').inherits;\n\nmodule.exports = SSE;\n\ninherits(SSE, Transform);\n\nfunction SSE(options) {\n  if (!(this instanceof SSE)) return new SSE(options);\n\n  options = options || {};\n  Transform.call(this, options);\n}\n\nSSE.prototype._transform = function(data, enc, cb) {\n  this.push('data: ' + data.toString('utf8') + '\\n\\n');\n  cb();\n};\n"
  },
  {
    "path": "stream-view/README.md",
    "content": "# stream-view\n\nThis is a \"Hello World\" application, using a view that inherits from a Readable stream.\n\nTo invoke, the following command begins listening on localhost:3000.\n\n    node app.js\n\nTo see results:\n\n    http://localhost:3000\n\n## Interesting points\n\n1. The main function of app.js instantiates a \"View\" from the view.js file.\n2. The View overrides the Readable's _read() function with an empty function.\n3. The View also overrides the Readable's render() function to do the following:\n  1. Immediately push out the text for the \\<head> of the page\n  2. Yield to a function that will ultimately (in the next tick) return the \"Hello World\" text. The render() function pauses at that point.\n  3. When that function returns, render() resumes, and assigns the return value to the `body` variable\n  4. Push out the returned text wrapped in \\<body> tags\n  5. Push out the closing \\</html> tag and\n  6. Close the connection with push(null)\n"
  },
  {
    "path": "stream-view/app.js",
    "content": "const Koa = require('koa');\n\nconst View = require('./view');\n\nconst app = module.exports = new Koa();\n\napp.use(async function(ctx) {\n  ctx.type = 'html';\n  ctx.body = new View(ctx);\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "stream-view/test.js",
    "content": "require('should');\nconst app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Stream View', function() {\n  after(function() {\n    server.close();\n  });\n\n  it('GET /', function(done) {\n    request\n    .get('/')\n    .expect(200, function(err, res) {\n      if (err) return done(err);\n\n      res.should.be.html;\n      res.text.should.include('<title>Hello World</title>');\n      res.text.should.include('<p>Hello World</p>');\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "stream-view/view.js",
    "content": "'use strict';\n\nconst Readable = require('stream').Readable;\nconst co = require('co');\n\nmodule.exports = class View extends Readable {\n\n  constructor(context) {\n    super();\n\n    // render the view on a different loop\n    co.call(this, this.render).catch(context.onerror);\n  }\n\n  _read() {}\n\n  *render() {\n    // push the <head> immediately\n    this.push('<!DOCTYPE html><html><head><title>Hello World</title></head>');\n\n    // render the <body> on the next tick\n    const body = yield done => {\n      setImmediate(() => done(null, '<p>Hello World</p>'));\n    };\n\n    this.push('<body>' + body + '</body>');\n\n    // close the document\n    this.push('</html>');\n\n    // end the stream\n    this.push(null);\n  };\n};\n"
  },
  {
    "path": "templates/app.js",
    "content": "const path = require('path');\nconst views = require('koa-views');\nconst Koa = require('koa');\nconst app = module.exports = new Koa();\n\n// setup views, appending .ejs\n// when no extname is given to render()\n\napp.use(views(path.join(__dirname, '/views'), { extension: 'ejs' }));\n\n// dummy data\n\nconst user = {\n  name: {\n    first: 'Tobi',\n    last: 'Holowaychuk'\n  },\n  species: 'ferret',\n  age: 3\n};\n\n// render\n\napp.use(async function(ctx) {\n  await ctx.render('user', { user });\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "templates/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Templates', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('GET /', function() {\n    it('should respond with a rendered view', function(done) {\n      request\n      .get('/')\n      .expect(200)\n      .expect('<p>Tobi is a 3 year old ferret.</p>', done);\n    });\n  });\n});\n"
  },
  {
    "path": "templates/views/user.ejs",
    "content": "<p><%= user.name.first %> is a <%= user.age %> year old <%= user.species %>.</p>"
  },
  {
    "path": "upload/app.js",
    "content": "\n/**\n * Module dependencies.\n */\n\nconst logger = require('koa-logger');\nconst serve = require('koa-static');\nconst koaBody = require('koa-body');\nconst Koa = require('koa');\nconst fs = require('fs');\nconst app = new Koa();\nconst os = require('os');\nconst path = require('path');\n\n// log requests\n\napp.use(logger());\n\napp.use(koaBody({ multipart: true }));\n\n// custom 404\n\napp.use(async function(ctx, next) {\n  await next();\n  if (ctx.body || !ctx.idempotent) return;\n  ctx.redirect('/404.html');\n});\n\n// serve files from ./public\n\napp.use(serve(path.join(__dirname, '/public')));\n\n// handle uploads\n\napp.use(async function(ctx, next) {\n  // ignore non-POSTs\n  if ('POST' != ctx.method) return await next();\n\n  const file = ctx.request.files.file;\n  const reader = fs.createReadStream(file.path);\n  const stream = fs.createWriteStream(path.join(os.tmpdir(), Math.random().toString()));\n  reader.pipe(stream);\n  console.log('uploading %s -> %s', file.name, stream.path);\n\n  ctx.redirect('/');\n});\n\n// listen\n\napp.listen(3000);\nconsole.log('listening on port 3000');\n"
  },
  {
    "path": "upload/public/404.html",
    "content": "<html>\n<head>\n  <title>Not Found</title>\n  <style>\n    body {\n      padding: 50px;\n      font: 14px Helvetica, Arial;\n    }\n  </style>\n</head>\n<body>\n  <h1>Sorry! Can't find that.</h1>\n  <p>The page you requested cannot be found.</p>\n</body>\n</html>"
  },
  {
    "path": "upload/public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <title>Upload</title>\n  <style>\n    body {\n      padding: 50px;\n      font: 14px Helvetica, Arial;\n    }\n  </style>\n</head>\n<body>\n  <h1>File Upload</h1>\n  <p>Try uploading multiple files at a time.</p>\n  <form action=\"/\" method=\"post\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"file\" multiple>\n    <input type=\"submit\" value=\"Upload\">\n  </form>\n</body>\n</html>"
  },
  {
    "path": "vhost/app.js",
    "content": "const compose = require('koa-compose');\nconst Koa = require('koa');\nconst app = module.exports = new Koa();\n\n// virtual host apps\n\nconst wwwSubdomain = composer(require('./apps/koa'));\nconst barSubdomain = composer(require('./apps/array'));\n\n// compose koa apps and middleware arrays\n// to be used later in our host switch generator\n\nfunction composer(app) {\n  const middleware = app instanceof Koa ? app.middleware : app;\n  return compose(middleware);\n}\n\n// look ma, global response logging for all our apps!\n\napp.use(async function(ctx, next) {\n  const start = new Date();\n  await next();\n  const ms = new Date() - start;\n  if ('test' != process.env.NODE_ENV) {\n    console.log('%s %s %s - %sms', ctx.host, ctx.method, ctx.url, ms);\n  }\n});\n\n// switch between appropriate hosts calling their\n// composed middleware with the appropriate context.\n\napp.use(async function(ctx, next) {\n  switch (ctx.hostname) {\n    case 'example.com':\n    case 'www.example.com':\n      // displays `Hello from main app`\n      // and sets a `X-Custom` response header\n      return await wwwSubdomain.apply(this, [ctx, next]);\n    case 'bar.example.com':\n      // displays `Howzit? From bar middleware bundle`\n      // and sets a `X-Response-Time` response header\n      return await barSubdomain.apply(this, [ctx, next]);\n  }\n\n  // everything else, eg: 127.0.0.1:3000\n  // will propagate to 404 Not Found\n  return await next();\n});\n\nif (!module.parent) app.listen(3000);\n"
  },
  {
    "path": "vhost/apps/array.js",
    "content": "// rather than koa apps we can also use array\n// bundles of middleware to the same effect.\n\nasync function responseTime(ctx, next) {\n  const start = new Date();\n  await next();\n  const ms = new Date() - start;\n  ctx.set('X-Response-Time', ms + 'ms');\n}\n\nasync function index(ctx, next) {\n  await next();\n  if ('/' != ctx.url) return;\n  ctx.body = 'Howzit? From bar middleware bundle';\n}\n\nmodule.exports = [\n  responseTime,\n  index\n];\n"
  },
  {
    "path": "vhost/apps/koa.js",
    "content": "const Koa = require('koa');\n\n// koa app\n\nconst app = new Koa();\n\napp.use(async function(ctx, next) {\n  await next();\n  ctx.set('X-Custom', 'Dub Dub Dub App');\n});\n\napp.use(async function(ctx, next) {\n  await next();\n  if ('/' != ctx.url) return;\n  ctx.body = 'Hello from www app';\n});\n\nmodule.exports = app;\n"
  },
  {
    "path": "vhost/test.js",
    "content": "const app = require('./app');\nconst server = app.listen();\nconst request = require('supertest').agent(server);\n\ndescribe('Virtual Host', function() {\n  after(function() {\n    server.close();\n  });\n\n  describe('www subdomain koa app', function() {\n    describe('when GET /', function() {\n      it('should say \"Hello from www app\"', function(done) {\n        request\n        .get('/')\n        .set('Host', 'www.example.com')\n        .expect(200)\n        .expect('Hello from www app', done);\n      });\n\n      it('should set X-Custom', function(done) {\n        request\n        .get('/')\n        .set('Host', 'www.example.com')\n        .expect('X-Custom', 'Dub Dub Dub App')\n        .expect(200, done);\n      });\n    });\n\n    describe('when GET / without subdomain', function() {\n      it('should say \"Hello from www app\"', function(done) {\n        request\n          .get('/')\n          .set('Host', 'example.com')\n          .expect(200)\n          .expect('Hello from www app', done);\n      });\n\n      it('should set X-Custom', function(done) {\n        request\n          .get('/')\n          .set('Host', 'example.com')\n          .expect('X-Custom', 'Dub Dub Dub App')\n          .expect(200, done);\n      });\n    });\n\n    describe('when not GET /', function() {\n      it('should 404', function(done) {\n        request\n        .get('/aklsjdf')\n        .set('Host', 'example.com')\n        .expect(404, done);\n      });\n    });\n  });\n  describe('bar subdomain array bundle', function() {\n    describe('when GET /', function() {\n      it('should say \"Howzit? From bar middleware bundle\"', function(done) {\n        request\n        .get('/')\n        .set('Host', 'bar.example.com')\n        .expect(200)\n        .expect('Howzit? From bar middleware bundle', done);\n      });\n\n      it('should set X-Response-Time', function(done) {\n        request\n        .get('/')\n        .set('Host', 'bar.example.com')\n        .expect('X-Response-Time', /ms$/)\n        .expect(200, done);\n      });\n    });\n\n    describe('when not GET /', function() {\n      it('should 404', function(done) {\n        request\n        .get('/aklsjdf')\n        .set('Host', 'bar.example.com')\n        .expect(404, done);\n      });\n    });\n  });\n  describe('default vhost', function() {\n    describe('when GET /', function() {\n      it('should 404', function(done) {\n        request\n        .get('/')\n        .set('Host', '127.0.0.1')\n        .expect(404, done);\n      });\n    });\n  });\n});\n"
  }
]