Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

server

Package Overview
Dependencies
Maintainers
1
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

server - npm Package Compare versions

Comparing version 1.0.0-alpha.27 to 1.0.0-alpha.28

1

others/file-upload.md

@@ -8,2 +8,3 @@ # Upload files to Node.js

input(type="file" name="userimage")
input(type="hidden" name="csrf" value=csrf())
input(type="submit" value="Upload image")

@@ -10,0 +11,0 @@ ```

2

package.json
{
"name": "server",
"version": "1.0.0-alpha.27",
"version": "1.0.0-alpha.28",
"description": "A modern and powerful server for Node.js",

@@ -5,0 +5,0 @@ "main": "server.js",

@@ -20,33 +20,16 @@ // External libraries used

// SKIP: request() does not accept gzip
it.skip('compress', done => {
const middle = ctx =>
ctx.res.send('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
launch(middle).then(ctx => {
supertest(ctx.original).get('/').then(res => {
done();
});
// expect(res.caseless.dict['content-length'] < 90).toBe(true);
// done();
});
});
it('compress?', () => {
it('compress?', async () => {
const middle = ctx => ctx.res.send();
const url = 'http://localhost:3721/favicon.ico';
const favicon = __dirname + '/../../tests/logo.png';
return handler(middle, { url }, { port: 3721, connect: { favicon } })
.then(res => expect(res.headers['content-encoding']).toBe('gzip'));
const res = await handler(middle, { url }, { port: 3721, connect: { favicon } });
expect(res.headers['content-encoding']).toBe('gzip');
});
it('favicon', () => {
it('favicon', async () => {
const middle = ctx => ctx.res.send();
const url = 'http://localhost:3721/favicon.ico';
const favicon = __dirname + '/../../tests/logo.png';
return handler(middle, { url }, { port: 3721, connect: { favicon } })
.then(res => expect(res.headers['content-type']).toBe('image/x-icon'));
const res = await handler(middle, { url }, { port: 3721, connect: { favicon } });
expect(res.headers['content-type']).toBe('image/x-icon');

@@ -57,36 +40,31 @@ // This should not go here:

it('response-time', () => {
it('response-time', async () => {
const middle = ctx => ctx.res.send('世界');
return getter(middle).then(res => {
expect(typeof res.headers['x-response-time']).toBe('string');
});
const res = await getter(middle);
expect(typeof res.headers['x-response-time']).toBe('string');
});
// GETTER doesn't have that signature
it('serve-index', done => {
it('serve-index', async () => {
const path = __dirname + '/../../tests';
return launch([], { public: path }).then(ctx => {
const logoUrl = 'http://localhost:' + ctx.options.port + '/logo.png';
request(logoUrl).then(res => {
expect(res.headers['content-type']).toBe('image/png');
done();
});
});
const ctx = await launch([], { public: path });
const logoUrl = 'http://localhost:' + ctx.options.port + '/logo.png';
const res = await request(logoUrl);
expect(res.headers['content-type']).toBe('image/png');
});
// NOTE: for the next tests we'd need persistent `request()` (I couldn't make it)
// Can handle sessions
it('session', done => {
it('session', async () => {
const setSession = ctx => { ctx.req.session.page = 'pageA' };
const routes = [
get('/a', ctx => { ctx.req.session.page = 'pageA'; ctx.res.end(); }),
get('/', ctx => ctx.res.send(ctx.req.session.page)),
get('/a', setSession, ctx => ctx.res.end()),
get('/b', ctx => ctx.res.send(ctx.req.session.page)),
];
launch(routes).then(req.get('/a')).then(req.get('/', res => {
expect(res.text).toBe('pageA');
done();
}));
const ctx = await launch(routes);
await req.get('/a', res => expect(res.text).toBe(''))(ctx);
await req.get('/b', res => expect(res.text).toBe('pageA'))(ctx);
});
it('csurf', done => {
it('csurf', async () => {
const routes = [

@@ -97,11 +75,22 @@ get('/', ctx => ctx.res.send(ctx.res.locals.csrf)),

launch(routes).then(ctx => {
supertest(ctx.server).get('/').expect(200).then(res => {
expect(res.text).toBeDefined();
supertest(ctx.server).post('/').set('Cookie', cookies(res))
.send('_csrf=' + encodeURIComponent(res.text))
.expect(200).then(() => done());
});
});
const ctx = await launch(routes);
const res = await supertest(ctx.server).get('/').expect(200);
expect(res.text).toBeDefined();
await supertest(ctx.server).post('/').set('Cookie', cookies(res))
.send('_csrf=' + encodeURIComponent(res.text))
.expect(200);
});
// SKIP: request() does not accept gzip
it.skip('compress', async () => {
const middle = ctx =>
ctx.res.send('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
const ctx = await launch(middle);
const res = await supertest(ctx.original).get('/');
// ...
});
});

@@ -16,68 +16,74 @@ // server for Node.js (https://serverjs.io/)

// Create the initial context
const context = (self, req = {}, res = {}) => {
return Object.assign({}, self, { req: req, res: res });
};
const context = (self, req, res) => Object.assign({}, self, { req, res });
// Main function
function Server (...middle) {
return new Promise((resolve, reject) => {
"use strict";
const Server = async (...middle) => {
// First parameter can be:
// - options: Number || Object (cannot be ID'd)
// - middleware: undefined || null || Boolean || Function || Array
const opts = (
typeof middle[0] === 'undefined' ||
typeof middle[0] === 'boolean' ||
middle[0] === null ||
middle[0] instanceof Function ||
middle[0] instanceof Array
) ? {} : middle.shift();
const ctx = {};
this.express = express;
this.app = this.express();
// First parameter can be:
// - options: Number || Object (cannot be ID'd)
// - middleware: undefined || null || Boolean || Function || Array
const opts = (
typeof middle[0] === 'undefined' ||
typeof middle[0] === 'boolean' ||
middle[0] === null ||
middle[0] instanceof Function ||
middle[0] instanceof Array
) ? {} : middle.shift();
// Set the options for the context of Server.js
this.plugins = module.exports.plugins;
this.options = config(opts, this.plugins, this.app);
ctx.express = express;
ctx.app = ctx.express();
this.utils = { modern: modern };
this.modern = modern;
// this.error = error(this.options.errors);
this.throw = error(this.options.errors);
// Set the options for the context of Server.js
ctx.options = config(opts, module.exports.plugins, ctx.app);
this.plugins.filter(p => p.init && this.options[p.name]).forEach(p => p.init(this));
// Only enabled plugins through the config
ctx.plugins = module.exports.plugins.filter(p => ctx.options[p.name]);
// PLUGIN middleware
middle = join(
this.plugins.filter(n => this.options[n.name]).map(p => p.beforeware || p.before),
middle,
this.plugins.filter(n => this.options[n.name]).map(p => p.afterware || p.after),
final
);
ctx.utils = { modern: modern };
ctx.modern = modern;
// ctx.error = error(ctx.options.errors);
ctx.throw = error(ctx.options.errors);
// Main thing here
this.app.use((req, res) => middle(context(this, req, res)));
// All the init beforehand
const initAll = ctx.plugins.map(p => p.init).filter(p => p);
for (let init of initAll) {
await init(ctx);
}
const launch = () => {
if (this.options.verbose) {
console.log(`Server started on port ${this.options.port} http://localhost:${this.options.port}/`);
// PLUGIN middleware
middle = join(
ctx.plugins.map(p => p.beforeware || p.before),
middle,
ctx.plugins.map(p => p.afterware || p.after),
final
);
// Main thing here
ctx.app.use((req, res) => middle(context(ctx, req, res)));
// Start listening to requests
return new Promise((resolve, reject) => {
const launch = async () => {
// After launching it
const launchAll = ctx.plugins.map(p => p.launch).filter(p => p);
for (let launch of launchAll) {
await launch(ctx);
}
// PLUGIN.attach: ctx => {}
if (ctx.options.verbose) {
ctx.log(`Server started on http://localhost:${ctx.options.port}/`);
}
// Proxy it to the server http-server for things like .close()
resolve(new Proxy(this, {
get: (ctx, key) => ctx[key] || ctx.server[key]
}));
resolve(new Proxy(ctx, { get: (orig, k) => orig[k] || orig.server[k] }));
};
// Start listening to requests
this.server = this.app.listen(this.options.port, launch);
this.server.on('error', err => reject(error.native(err)));
ctx.server = ctx.app.listen(ctx.options.port, launch);
ctx.server.on('error', err => reject(error.native(err)));
});
}
module.exports = (...opts) => new Server(...opts);
module.exports = Server;
module.exports.router = router;

@@ -84,0 +90,0 @@ module.exports.utils = {

@@ -87,3 +87,3 @@ const config = require('./index');

it('sets values to the app', done => {
it('sets values to the app', () => {
config({ foo: 'bar' }, [], {

@@ -93,3 +93,2 @@ set: (name, value) => {

expect(value).toBe('bar');
done();
}

@@ -96,0 +95,0 @@ }

@@ -0,1 +1,4 @@

const buffer = require('crypto').randomBytes(60);
const token = buffer.toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
// Default configuration for server

@@ -8,6 +11,5 @@ module.exports = {

public: 'public',
secret: 'secret-' + parseInt(1000000 * Math.random()),
secret: 'secret-' + token,
// Dev variables - not part of the official API

@@ -14,0 +16,0 @@ // Show extra info on the terminal; should depend on another variable

@@ -49,4 +49,12 @@ const extend = require('extend'); // deep clone, not like shallow Object.assign

if ((/^secret-/.test(options.secret)) && options.verbose) {
console.log(`
Please change the secret in your environment configuration.
The default one is not recommended and should be changed.
More info in https://serverjs.io/errors#defaultSecret
`);
}
if (app) {

@@ -53,0 +61,0 @@ app.options = options;

const join = require('../join');
const modern = require('./index');
const { throws } = require('../../tests/helpers');
const middle = (req, res, next) => next();

@@ -33,5 +34,5 @@ const ctx = { req: {}, res: {} };

describe('call the middleware', () => {
it('requires the context to be called', done => {
modern(middle)().catch(err => { done(); });
});
it('requires the context to be called', throws(async () => {
await modern(middle)();
}));

@@ -42,13 +43,13 @@ it('returns a promise when called', () => {

it('rejected with empty context', done => {
modern(middle)({}).catch(err => { done(); });
});
it('rejected with empty context', throws(async () => {
await modern(middle)({});
}));
it('rejected without res', done => {
modern(middle)({ req: {} }).catch(err => { done(); });
});
it('rejected without res', throws(async () => {
await modern(middle)({ req: {} });
}));
it('rejected without req', done => {
modern(middle)({ res: {} }).catch(err => { done(); });
});
it('rejected without req', throws(async () => {
await modern(middle)({ res: {} });
}));
});

@@ -59,20 +60,18 @@

describe('Middleware handles the promise', () => {
it('resolves when next is called empty', done => {
modern((req, res, next) => next())(ctx).then(() => done());
it('resolves when next is called empty', async () => {
await modern((req, res, next) => next())(ctx);
});
it('cannot handle error middleware', () => {
expect(() => modern((err, req, res, next) => {})).toThrow();
});
it('cannot handle error middleware', throws(async () => {
await modern((err, req, res, next) => {});
}));
it('passes the context', done => {
it('passes the context', async () => {
const ctx = { req: 1, res: 2 };
modern((req, res, next) => next())(ctx).then(ctx => {
expect(ctx.req).toBe(1);
expect(ctx.res).toBe(2);
done();
});
const readCtx = await modern((req, res, next) => next())(ctx);
expect(readCtx.req).toBe(1);
expect(readCtx.res).toBe(2);
});
it('can modify the context', done => {
it('can modify the context', async () => {
const middle = (req, res, next) => {

@@ -83,10 +82,8 @@ req.user = 'myname';

};
modern(middle)({ req: {}, res: {} }).then(ctx => {
expect(ctx.req.user).toBe('myname');
expect(ctx.res.send).toBe('sending');
done();
});
const ctx = await modern(middle)({ req: {}, res: {} });
expect(ctx.req.user).toBe('myname');
expect(ctx.res.send).toBe('sending');
});
it('has chainable context', done => {
it('has chainable context', async () => {
const ctx = { req: { user: 'a' }, res: { send: 'b' } };

@@ -98,10 +95,8 @@ const middle = (req, res, next) => {

};
modern(middle)(ctx).then(modern(middle)).then(ctx => {
expect(ctx.req.user).toBe('a11');
expect(ctx.res.send).toBe('b22');
done();
});
const resCtx = await modern(middle)(ctx).then(modern(middle));
expect(resCtx.req.user).toBe('a11');
expect(resCtx.res.send).toBe('b22');
});
it('factory can receive options', done => {
it('factory can receive options', async () => {

@@ -164,17 +159,12 @@ // The full context

join(middles)(ctx).then(ctx => {
expect(ctx.req.user).toBe('a111111');
expect(ctx.res.send).toBe('b111111');
done();
});
const readCtx = await join(middles)(ctx);
expect(readCtx.req.user).toBe('a111111');
expect(readCtx.res.send).toBe('b111111');
});
it('rejects when next is called with an error', done => {
modern((req, res, next) => next('Custom error'))(ctx).catch(err => {
expect(err).toBe('Custom error');
done();
});
});
it('rejects when next is called with an error', throws(async () => {
await modern((req, res, next) => next(new Error('Custom error')))(ctx);
}));
it('does not resolve nor reject if next is not called', done => {
it('does not resolve nor reject if next is not called', async () => {
modern((req, res, next) => {})(ctx).then(ctx => {

@@ -185,4 +175,6 @@ expect('It was resolved').toBe(false);

});
setTimeout(() => done(), 1000);
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 1000);
});
});
});

@@ -48,11 +48,9 @@ const extend = require('extend');

it('still works?', done => {
it('still works?', async () => {
const ctx = createCtx();
ctx.req.path = '/test/francisco/presencia/bla';
get('/test/:name/:lastname/bla')(ctx).then(ctx => {
expect(ctx.req.solved).toBe(true);
expect(ctx.req.params.name).toBe('francisco');
expect(ctx.req.params.lastname).toBe('presencia');
done();
});
let relCtx = await get('/test/:name/:lastname/bla')(ctx);
expect(relCtx.req.solved).toBe(true);
expect(relCtx.req.params.name).toBe('francisco');
expect(relCtx.req.params.lastname).toBe('presencia');
});

@@ -59,0 +57,0 @@ });

@@ -88,1 +88,13 @@ const request = require('request');

exports.cookies = cookies;
exports.throws = (cb, err = false) => async () => {
try {
const res = await cb();
} catch(err) {
if (!(err instanceof Error)) {
throw new Error('A non-error was thrown: ' + err);
}
return Promise.resolve();
}
throw new Error('No error was thrown');
};

@@ -1,69 +0,78 @@

let server = require('../server');
const server = require('../server');
const { port } = require('./helpers');
describe('Options', () => {
it('default settings are correct', () => {
return server().then(server => {
expect(server.options.port).toBe(3000);
expect(server.options.engine).toBe('pug');
expect(server.options.verbose).toBe(false);
it('default settings are correct', async () => {
const ctx = await server();
ctx.close();
expect(ctx.options.port).toBe(3000);
expect(ctx.options.engine).toBe('pug');
expect(ctx.options.verbose).toBe(false);
expect(ctx.options.secret).toMatch(/^secret-/);
});
// Now this is a plugin:
// expect(server.options.public).toBe('public');
server.close();
});
it('accepts a single port Number', async () => {
const options = port();
const ctx = await server(options);
ctx.close();
expect(ctx.options.port).toBe(options);
});
it('can be initialized with a single port parameter', done => {
let port = 3000 + parseInt(Math.random() * 10000) % 1000;
server(port).then(server => {
expect(server.options.port).toBe(port);
server.close();
done();
});
it('accepts a simple Object with a port prop', async () => {
const options = { port: port() };
const ctx = await server(options);
ctx.close();
expect(ctx.options.port).toBe(options.port);
});
it('can be initialized with only a port', done => {
let port = 3000 + parseInt(Math.random() * 10000) % 1000;
server({ port: port }).then(server => {
expect(server.options.port).toBe(port);
server.close();
done();
});
it('can listen only one time to the same port', async () => {
const onePort = port();
const ctx = await server(onePort);
const err = await server(onePort).catch(err => err);
ctx.close();
expect(err.code === 'EADDRINUSE');
});
it('can listen only one time to the same port', done => {
server(3000).then(serve => {
server(3000).catch(error => {
expect(error.code === 'EADDRINUSE')
done();
});
serve.close();
});
it('sets the engine properly `engine`', async () => {
const ctx = await server({ engine: 'whatever', port: port() });
ctx.close();
expect(ctx.app.get('view engine')).toBe('whatever');
});
it('sets the view engine properly', done => {
server({ 'view engine': 'whatever' }).then(server => {
expect(server.app.get('view engine')).toBe('whatever');
server.close();
done();
});
it('sets the engine properly `view engine`', async () => {
const ctx = await server({ 'view engine': 'whatever', port: port() });
ctx.close();
expect(ctx.app.get('view engine')).toBe('whatever');
});
it('has independent instances', done => {
server(2051).then(serv1 => {
server(3051).then(serv2 => {
expect(serv2.options.port).toBe(3051);
serv2.options.port = 3500;
expect(serv1.options.port).toBe(2051);
expect(serv2.options.port).toBe(3500);
it('has independent instances', async () => {
const portA = port();
const portB = port();
const serv1 = await server(portA);
const serv2 = await server(portB);
serv1.close();
serv2.close();
serv2.a = 'abc';
expect(typeof serv1.a).toBe('undefined');
expect(serv2.a).toBe('abc');
serv1.close();
serv2.close();
done();
});
});
expect(serv2.options.port).toBe(portB);
const portC = port();
serv2.options.port = portC;
expect(serv1.options.port).toBe(portA);
expect(serv2.options.port).toBe(portC);
serv2.a = 'abc';
expect(typeof serv1.a).toBe('undefined');
expect(serv2.a).toBe('abc');
});
// // NOT PART OF THE STABLE API
// it('logs init string', async () => {
// const logs = [];
// const index = server.plugins.push({
// name: 'log', launch: ctx => { ctx.log = msg => logs.push(msg) }
// });
// const ctx = await server({ port: port(), verbose: true });
// ctx.close();
// delete server.plugins[index];
// expect(logs.filter(one => /started on/.test(one)).length).toBe(1);
// });
});

@@ -8,6 +8,5 @@ const server = require('server');

const { get, error } = server.router;
const { handler, getter } = require('./helpers');
const { handler, getter, port } = require('./helpers');
const hello = ctx => ctx.res.send('Hello 世界');
const randPort = ctx => ctx.options.port = 2000 + parseInt(Math.random() * 10000);

@@ -21,50 +20,32 @@ const wait = time => new Promise((resolve, reject) => setTimeout(resolve, time));

describe('Middleware', () => {
it('loads as a function', done => {
getter(ctx => ctx.res.send('Hello 世界')).then(res => {
expect(res.body).toBe('Hello 世界');
done();
});
it('loads as a function', async () => {
const res = await getter(ctx => ctx.res.send('Hello 世界'));
expect(res.body).toBe('Hello 世界');
});
it('loads as an array', done => {
getter([ctx => ctx.res.send('Hello 世界')]).then(res => {
expect(res.body).toBe('Hello 世界');
done();
});
it('loads as an array', async () => {
const res = await getter([ctx => ctx.res.send('Hello 世界')]);
expect(res.body).toBe('Hello 世界');
});
// NOTE: port has to be changed for parallel tests
it('loads as an function in the first parameter', () => {
server.plugins.push({ init: ctx => {
ctx.options.port = 2000 + parseInt(Math.random() * 10000);
}});
return server(hello).then(autorequest).then(res => {
expect(res.body).toBe('Hello 世界');
});
});
// it('loads as an array in the first parameter', () => {
// // After others have finished
// return wait(1000).then(() => {
// server([hello]).then(autorequest).then(res => {
// expect(res.body).toBe('Hello 世界');
// });
// });
// });
it('loads as an array in the first parameter', () => {
// After others have finished
return wait(1000).then(() => {
server([hello]).then(autorequest).then(res => {
expect(res.body).toBe('Hello 世界');
});
it('has a valid context', async () => {
const res = await getter(({ req, res, options }) => {
res.send(`${!!req}:${!!options}`);
});
expect(res.body).toBe('true:true');
});
it('has a valid context', () => {
return getter(ctx => {
ctx.res.send('Hello');
expect(ctx.req).toBeDefined();
expect(ctx.res).toBeDefined();
expect(ctx.options).toBeDefined();
});
it('loads as a relative file', async () => {
const res = await handler('./tests/a.js');
expect(res.body).toBe('世界');
});
it('loads as a relative file', done => {
handler('./tests/a.js').then(res => {
expect(res.body).toBe('世界');
done();
});
});
});

@@ -13,6 +13,2 @@ const request = require('request-promise-native');

describe('Full trip request', () => {
it('dummy', done => {
done();
});
it('can perform a simple get', () => {

@@ -24,11 +20,9 @@ return getter(ctx => ctx.res.send('Hello 世界')).then(res => {

it('loads as an array', done => {
getter([ctx => ctx.res.send('Hello 世界')]).then(res => {
expect(res.body).toBe('Hello 世界');
done();
});
it('loads as an array', async () => {
const res = await getter([ctx => ctx.res.send('Hello 世界')]);
expect(res.body).toBe('Hello 世界');
});
it('can perform a simple post', () => {
let reply = ctx => ctx.res.send('Hello ' + ctx.req.body.a);
const reply = ctx => ctx.res.send('Hello ' + ctx.req.body.a);
return poster(reply, { a: '世界' }, nocsrf).then(res => {

@@ -35,0 +29,0 @@ expect(res.body).toBe('Hello 世界');

@@ -67,8 +67,6 @@ const request = require('request-promise-native');

// multiple request to make sure the middleware remains the same
it('parses params correctly', done => {
it('parses params correctly', async () => {
const middle = get('/:id', ctx => ctx.res.send(ctx.req.params.id));
handler(middle, { path: '/42?ignored=true' }).then(res => {
expect(res.body).toBe('42');
done();
});
const res = await handler(middle, { path: '/42?ignored=true' });
expect(res.body).toBe('42');
});

@@ -78,11 +76,9 @@

// multiple request to make sure the middleware remains the same
it('does not modify the router', done => {
launch([get('/w', ctx => ctx.res.send('w'))].concat(routes)).then(ctx => {
const url = 'http://localhost:' + ctx.options.port + '/';
request(url).then(() => request(url)).then(() => request(url)).then(body => {
ctx.close();
expect(body).toBe('Hello 世界')
done();
});
});
it('does not modify the router', async () => {
const ctx = await launch([get('/w', ctx => ctx.res.send('w'))].concat(routes));
const full = 'http://localhost:' + ctx.options.port + '/';
for (let url of [full, full, full]) {
let body = await request(url);
expect(body).toBe('Hello 世界');
}
});

@@ -89,0 +85,0 @@ });

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc