mirror of
https://github.com/abrendan/MicDropMessages.git
synced 2025-08-25 14:02:03 +02:00
Initial commit
This commit is contained in:
16
node_modules/server/plugins/compress/index.js
generated
vendored
Normal file
16
node_modules/server/plugins/compress/index.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
const modern = require('../../src/modern');
|
||||
const compress = require('compression');
|
||||
|
||||
module.exports = {
|
||||
name: 'compress',
|
||||
options: {
|
||||
__root: 'compress',
|
||||
compress: {
|
||||
default: {},
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
|
||||
// The whole plugin won't be loaded if the option is false
|
||||
before: ctx => modern(compress(ctx.options.compress))(ctx)
|
||||
};
|
18
node_modules/server/plugins/compress/integration.test.js
generated
vendored
Normal file
18
node_modules/server/plugins/compress/integration.test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
const run = require('server/test/run');
|
||||
|
||||
describe('compress', () => {
|
||||
it('works with the defaults', async () => {
|
||||
const res = await run(() => 'Hello world').get('/');
|
||||
expect(res.body).toBe('Hello world');
|
||||
});
|
||||
|
||||
it('works with an empty option object', async () => {
|
||||
const res = await run({ compress: {} }, () => 'Hello world').get('/');
|
||||
expect(res.body).toBe('Hello world');
|
||||
});
|
||||
|
||||
it('works without compress', async () => {
|
||||
const res = await run({ compress: false }, () => 'Hello world').get('/');
|
||||
expect(res.body).toBe('Hello world');
|
||||
});
|
||||
});
|
68
node_modules/server/plugins/express/index.js
generated
vendored
Normal file
68
node_modules/server/plugins/express/index.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
const express = require('express');
|
||||
|
||||
module.exports = {
|
||||
name: 'express',
|
||||
options: {
|
||||
// See these in-depth in https://expressjs.com/en/api.html#app.set
|
||||
'case sensitive routing': {},
|
||||
'env': {
|
||||
inherit: 'env'
|
||||
},
|
||||
'etag': {},
|
||||
'jsonp callback name': {},
|
||||
'json replacer': {},
|
||||
'json spaces': {},
|
||||
'query parser': {},
|
||||
'strict routing': {},
|
||||
'subdomain offset': {},
|
||||
'trust proxy': {},
|
||||
'views': {
|
||||
default: 'views',
|
||||
inherit: true,
|
||||
type: String,
|
||||
folder: true
|
||||
},
|
||||
'view cache': {},
|
||||
'view engine': {
|
||||
inherit: 'engine'
|
||||
},
|
||||
'x-powered-by': {}
|
||||
},
|
||||
init: ctx => {
|
||||
ctx.express = express;
|
||||
ctx.app = ctx.express();
|
||||
|
||||
// Go through all of the options and set the right ones
|
||||
for (let key in ctx.options.express) {
|
||||
let value = ctx.options.express[key];
|
||||
if (typeof value !== 'undefined') {
|
||||
ctx.app.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Accept HTML as a render extension
|
||||
ctx.app.engine('html', require('hbs').__express);
|
||||
|
||||
if (ctx.options.engine) {
|
||||
// If it's an object, expect a { engine: { engineName: engineFN } }
|
||||
if (typeof ctx.options.engine === 'object') {
|
||||
for (let name in ctx.options.engine) {
|
||||
ctx.app.engine(name, ctx.options.engine[name]);
|
||||
ctx.app.set('view engine', name);
|
||||
}
|
||||
} else { // Simple case like { engine: 'pug' }
|
||||
ctx.app.set('view engine', ctx.options.engine);
|
||||
}
|
||||
}
|
||||
},
|
||||
listen: ctx => new Promise((resolve, reject) => {
|
||||
ctx.server = ctx.app.listen(ctx.options.port, () => {
|
||||
ctx.log.debug(`Server started on http://localhost:${ctx.options.port}/`);
|
||||
resolve();
|
||||
});
|
||||
ctx.close = () => new Promise((res, rej) => {
|
||||
ctx.server.close(err => err ? rej(err) : res());
|
||||
});
|
||||
ctx.server.on('error', err => reject(err));
|
||||
})
|
||||
};
|
56
node_modules/server/plugins/express/integration.test.js
generated
vendored
Normal file
56
node_modules/server/plugins/express/integration.test.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
const server = require('../../server');
|
||||
const { status } = server.reply;
|
||||
|
||||
// Test runner:
|
||||
const run = require('server/test/run');
|
||||
|
||||
describe('express', () => {
|
||||
it('is defined', () => {
|
||||
server(parseInt(1000 + Math.random() * 10000)).then(ctx => {
|
||||
expect(ctx.app).toBeDefined();
|
||||
ctx.close();
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts the options', async () => {
|
||||
|
||||
const options = {
|
||||
'case sensitive routing': true,
|
||||
'etag': 'strong',
|
||||
'jsonp callback name': 'abc',
|
||||
'subdomain offset': 1,
|
||||
'trust proxy': true,
|
||||
'view cache': true,
|
||||
'x-powered-by': false
|
||||
};
|
||||
|
||||
const res = await run({ express: options }, ctx => {
|
||||
for (let key in options) {
|
||||
expect(ctx.app.get(key)).toBe(options[key]);
|
||||
}
|
||||
return status(200);
|
||||
}).get('/');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toBe('');
|
||||
});
|
||||
|
||||
it('ignores the view engine (use .engine instead)', async () => {
|
||||
const res = await run({ express: { 'view engine': 'abc' } }, ctx => {
|
||||
expect(ctx.app.get('env')).toBe('test');
|
||||
expect(ctx.app.get('view engine')).toBe('pug');
|
||||
return status(200);
|
||||
}).get('/');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toBe('');
|
||||
});
|
||||
|
||||
it.skip('uses an engine', async () => {
|
||||
const res = run({
|
||||
express: { engine: {
|
||||
blabla: 'I do not know how to make an engine yet'
|
||||
}}
|
||||
}).get('/');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toBe('');
|
||||
});
|
||||
});
|
21
node_modules/server/plugins/favicon/index.js
generated
vendored
Normal file
21
node_modules/server/plugins/favicon/index.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const modern = require('../../src/modern');
|
||||
const favicon = require('serve-favicon');
|
||||
|
||||
module.exports = {
|
||||
name: 'favicon',
|
||||
options: {
|
||||
__root: 'location',
|
||||
location: {
|
||||
type: String,
|
||||
file: true,
|
||||
env: 'FAVICON'
|
||||
}
|
||||
},
|
||||
|
||||
before: [
|
||||
ctx => {
|
||||
if (!ctx.options.favicon.location) return false;
|
||||
return modern(favicon(ctx.options.favicon.location))(ctx);
|
||||
}
|
||||
]
|
||||
};
|
16
node_modules/server/plugins/favicon/integration.test.js
generated
vendored
Normal file
16
node_modules/server/plugins/favicon/integration.test.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
const run = require('server/test/run');
|
||||
|
||||
const favicon = 'test/logo.png';
|
||||
|
||||
describe('Default modules', () => {
|
||||
it('favicon', async () => {
|
||||
const res = await run({ favicon }).get('/favicon.ico');
|
||||
expect(res.headers['content-type']).toBe('image/x-icon');
|
||||
});
|
||||
|
||||
// TODO: test for non-existing
|
||||
|
||||
// TODO: test different locations
|
||||
|
||||
// TODO: test for env
|
||||
});
|
40
node_modules/server/plugins/final/errors.js
generated
vendored
Normal file
40
node_modules/server/plugins/final/errors.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
const error = require('../../error')('/plugin/final/');
|
||||
|
||||
error.noreturn = ({ method, url }) => `
|
||||
Your middleware did not return anything for this request:
|
||||
|
||||
${method} ${url}
|
||||
|
||||
This normally happens when no route was matched or if the router did not reply with anything. Make sure to return something, even if it's a catch-all error.
|
||||
|
||||
Documentation for reply: https://serverjs.io/documentation/reply/
|
||||
Relevant issue: https://github.com/franciscop/server/issues/118
|
||||
`;
|
||||
|
||||
error.unhandled = `
|
||||
Some middleware threw an error that was not handled properly. This can happen when you do this:
|
||||
|
||||
~~~
|
||||
// BAD:
|
||||
server(ctx => { throw new Error('I am an error!'); });
|
||||
~~~
|
||||
|
||||
To catch and handle these types of errors, add a route to the end of your middlewares to handle errors like this:
|
||||
|
||||
~~~
|
||||
// GOOD:
|
||||
const { error } = server.router;
|
||||
const { status } = server.reply;
|
||||
|
||||
server(
|
||||
ctx => { throw new Error('I am an error!'); },
|
||||
// ...
|
||||
error(ctx => status(500).send(ctx.error.message))
|
||||
);
|
||||
~~~
|
||||
|
||||
Please feel free to open an issue in Github asking for more info:
|
||||
https://github.com/franciscop/server
|
||||
`;
|
||||
|
||||
module.exports = error;
|
68
node_modules/server/plugins/final/final.test.js
generated
vendored
Normal file
68
node_modules/server/plugins/final/final.test.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
const run = require('server/test/run');
|
||||
|
||||
// Note: the `raw` option only works for tests
|
||||
|
||||
const storeLog = out => ({ report: { write: log => { out.log = log; } } });
|
||||
|
||||
describe('final', () => {
|
||||
it('gets called with an unhandled error', async () => {
|
||||
const simple = () => { throw new Error('Hello Error'); };
|
||||
const out = {};
|
||||
const res = await run({ raw: true, log: storeLog(out) }, simple).get('/');
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body).toBe('Internal Server Error');
|
||||
expect(out.log).toMatch('Hello Error');
|
||||
});
|
||||
|
||||
it('just logs it if the headers were already sent', async () => {
|
||||
const simple = () => { throw new Error('Hello Error'); };
|
||||
const out = {};
|
||||
const res = await run({ raw: true, log: storeLog(out) }, () => 'Hello world', simple).get('/');
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toBe('Hello world');
|
||||
expect(out.log).toMatch('Hello Error');
|
||||
});
|
||||
|
||||
it('displays the appropriate error to the public', async () => {
|
||||
const simple = () => {
|
||||
const err = new Error('Hello Error: display to the public');
|
||||
err.public = true;
|
||||
throw err;
|
||||
};
|
||||
const out = {};
|
||||
const res = await run({ raw: true, log: storeLog(out) }, simple).get('/');
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body).toBe('Hello Error: display to the public');
|
||||
expect(out.log).toMatch('Hello Error');
|
||||
});
|
||||
|
||||
it('makes the status 500 if it is invalid', async () => {
|
||||
const simple = () => {
|
||||
const err = new Error('Hello Error');
|
||||
err.status = 'pepito';
|
||||
throw err;
|
||||
};
|
||||
const out = {};
|
||||
const res = await run({ raw: true, log: storeLog(out) }, simple).get('/');
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body).toBe('Internal Server Error');
|
||||
expect(out.log).toMatch('Hello Error');
|
||||
});
|
||||
|
||||
it('does not reply if the headers are already sent', async () => {
|
||||
const simple = ctx => {
|
||||
ctx.res.send('Error 世界');
|
||||
throw new Error('Hello');
|
||||
};
|
||||
const res = await run(simple).get('/');
|
||||
expect(res.body).toBe('Error 世界');
|
||||
});
|
||||
|
||||
it('handles non-existing requests to a 404', async () => {
|
||||
const out = {};
|
||||
const res = await run({ log: storeLog(out) }).get('/non-existing');
|
||||
|
||||
expect(res.statusCode).toBe(404);
|
||||
expect(out.log).toMatch(/did not return anything/);
|
||||
});
|
||||
});
|
44
node_modules/server/plugins/final/index.js
generated
vendored
Normal file
44
node_modules/server/plugins/final/index.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// This file makes sure to clean up things in case there was something missing
|
||||
// There are two reasons normally for this to happen: no reply was set or an
|
||||
// unhandled error was thrown
|
||||
const FinalError = require('./errors');
|
||||
|
||||
// Make sure that a (404) reply is sent if there was no user reply
|
||||
const handler = async ctx => {
|
||||
if (!ctx.res.headersSent) {
|
||||
// Send the user-set status
|
||||
ctx.res.status(ctx.res.explicitStatus ? ctx.res.statusCode : 404).send();
|
||||
|
||||
// Show it only if there was no status set in a return
|
||||
if (!ctx.res.explicitStatus) {
|
||||
ctx.log.error(
|
||||
new FinalError('noreturn', { url: ctx.url, method: ctx.method })
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Make sure there is a (500) reply if there was an unhandled error thrown
|
||||
handler.error = ctx => {
|
||||
const error = ctx.error;
|
||||
ctx.log.warning(FinalError('unhandled'));
|
||||
ctx.log.error(error);
|
||||
if (!ctx.res.headersSent) {
|
||||
let status = error.status || error.code || 500;
|
||||
if (typeof status !== 'number') status = 500;
|
||||
|
||||
// Display the error message if this error is marked as public
|
||||
if (error.public) {
|
||||
return ctx.res.status(status).send(error.message);
|
||||
}
|
||||
|
||||
// Otherwise just display the default error for that code
|
||||
ctx.res.sendStatus(status);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
name: 'final',
|
||||
after: handler
|
||||
};
|
||||
// module.exports = handler;
|
33
node_modules/server/plugins/log/index.js
generated
vendored
Normal file
33
node_modules/server/plugins/log/index.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
const Log = require('log');
|
||||
|
||||
const valid = [
|
||||
'emergency',
|
||||
'alert',
|
||||
'critical',
|
||||
'error',
|
||||
'warning',
|
||||
'notice',
|
||||
'info',
|
||||
'debug'
|
||||
];
|
||||
|
||||
// Log plugin
|
||||
const plugin = {
|
||||
name: 'log',
|
||||
options: {
|
||||
__root: 'level',
|
||||
level: {
|
||||
default: 'info',
|
||||
type: String,
|
||||
enum: valid
|
||||
},
|
||||
report: {
|
||||
default: process.stdout
|
||||
}
|
||||
},
|
||||
init: ctx => {
|
||||
ctx.log = new Log(ctx.options.log.level, ctx.options.log.report);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = plugin;
|
47
node_modules/server/plugins/log/integration.test.js
generated
vendored
Normal file
47
node_modules/server/plugins/log/integration.test.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const server = require('../../server');
|
||||
const { status } = server.reply;
|
||||
const ConfigError = require('server/src/config/errors');
|
||||
|
||||
// Test runner:
|
||||
const run = require('server/test/run');
|
||||
|
||||
describe('log()', () => {
|
||||
it('is defined', () => {
|
||||
server(parseInt(1000 + Math.random() * 10000)).then(ctx => {
|
||||
expect(ctx.log).toBeDefined();
|
||||
ctx.close();
|
||||
});
|
||||
});
|
||||
|
||||
it('is inside the middleware', async () => {
|
||||
const res = await run(ctx => status(ctx.log ? 200 : 500)).get('/');
|
||||
expect(res.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it('has the right methods', async () => {
|
||||
const res = await run(ctx => {
|
||||
expect(ctx.log.emergency).toBeDefined();
|
||||
expect(ctx.log.alert).toBeDefined();
|
||||
expect(ctx.log.critical).toBeDefined();
|
||||
expect(ctx.log.error).toBeDefined();
|
||||
expect(ctx.log.warning).toBeDefined();
|
||||
expect(ctx.log.notice).toBeDefined();
|
||||
expect(ctx.log.info).toBeDefined();
|
||||
expect(ctx.log.debug).toBeDefined();
|
||||
return status(200);
|
||||
}).get('/');
|
||||
expect(res.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it('rejects invalid log levels', async () => {
|
||||
const res = run({ log: 'abc' }).get('/');
|
||||
|
||||
// Now errors must be fully qualified with Jest
|
||||
expect(res).rejects.toMatchObject(new ConfigError('enum', {
|
||||
name: 'level',
|
||||
value: 'abc',
|
||||
possible: ['emergency','alert','critical','error','warning','notice','info','debug'],
|
||||
status: 500
|
||||
}));
|
||||
});
|
||||
});
|
97
node_modules/server/plugins/parser/index.js
generated
vendored
Normal file
97
node_modules/server/plugins/parser/index.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// Parser plugin
|
||||
// Get the raw request and transform it into something usable
|
||||
// Examples: ctx.body, ctx.files, etc
|
||||
const join = require('../../src/join');
|
||||
const modern = require('../../src/modern');
|
||||
|
||||
const plugin = {
|
||||
name: 'parser',
|
||||
options: {
|
||||
body: {
|
||||
type: [Object, Boolean],
|
||||
default: { extended: true },
|
||||
extend: true
|
||||
},
|
||||
json: {
|
||||
type: [Object, Boolean],
|
||||
default: {}
|
||||
},
|
||||
text: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
cookie: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
method: {
|
||||
type: [Object, String, Boolean],
|
||||
default: [
|
||||
'X-HTTP-Method',
|
||||
'X-HTTP-Method-Override',
|
||||
'X-Method-Override',
|
||||
'_method'
|
||||
],
|
||||
// Coerce it into an Array if it is not already
|
||||
clean: value => typeof value === 'string' ? [value] : value
|
||||
}
|
||||
},
|
||||
|
||||
// It is populated in "init()" right now:
|
||||
before: [
|
||||
ctx => {
|
||||
if (!ctx.options.parser.method) return;
|
||||
return join(ctx.options.parser.method.map(one => {
|
||||
return modern(require('method-override')(one));
|
||||
}))(ctx);
|
||||
},
|
||||
|
||||
ctx => {
|
||||
if (!ctx.options.parser.body) return;
|
||||
const body = require('body-parser').urlencoded(ctx.options.parser.body);
|
||||
return modern(body)(ctx);
|
||||
},
|
||||
|
||||
// JSON parser
|
||||
ctx => {
|
||||
if (!ctx.options.parser.json) return;
|
||||
const json = require('body-parser').json(ctx.options.parser.json);
|
||||
return modern(json)(ctx);
|
||||
},
|
||||
|
||||
// Text parser
|
||||
ctx => {
|
||||
if (!ctx.options.parser.text) return;
|
||||
const text = require('body-parser').text(ctx.options.parser.text);
|
||||
return modern(text)(ctx);
|
||||
},
|
||||
|
||||
// Data parser
|
||||
ctx => {
|
||||
if (!ctx.options.parser.data) return;
|
||||
const data = require('express-data-parser')(ctx.options.parser.data);
|
||||
return modern(data)(ctx);
|
||||
},
|
||||
|
||||
// Cookie parser
|
||||
ctx => {
|
||||
if (!ctx.options.parser.cookie) return;
|
||||
const cookie = require('cookie-parser')(
|
||||
ctx.options.secret,
|
||||
ctx.options.parser.cookie
|
||||
);
|
||||
return modern(cookie)(ctx);
|
||||
},
|
||||
|
||||
// Add a reference from ctx.req.body to the ctx.data and an alias
|
||||
ctx => {
|
||||
ctx.data = ctx.body;
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
module.exports = plugin;
|
121
node_modules/server/plugins/parser/integration.test.js
generated
vendored
Normal file
121
node_modules/server/plugins/parser/integration.test.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// External libraries used
|
||||
const { cookie } = require('server/reply');
|
||||
const run = require('server/test/run');
|
||||
const fs = require('fs');
|
||||
run.options = { security: false };
|
||||
|
||||
// Local helpers and data
|
||||
const logo = fs.createReadStream(__dirname + '/../../test/logo.png');
|
||||
const content = ctx => ctx.headers['content-type'];
|
||||
|
||||
|
||||
describe('Default modules', () => {
|
||||
|
||||
it('bodyParser', async () => {
|
||||
const mid = ctx => {
|
||||
expect(ctx.data).toEqual(ctx.req.body);
|
||||
expect(ctx.data).toBeDefined();
|
||||
expect(ctx.data.hello).toBe('世界');
|
||||
expect(content(ctx)).toBe('application/x-www-form-urlencoded');
|
||||
return 'Hello 世界';
|
||||
};
|
||||
|
||||
const res = await run(mid).post('/', { form: 'hello=世界' });
|
||||
expect(res.body).toBe('Hello 世界');
|
||||
});
|
||||
|
||||
it('dataParser', async () => {
|
||||
const mid = ctx => ctx.files.logo;
|
||||
const res = await run(mid).post('/', { formData: { logo } });
|
||||
|
||||
expect(res.body.name).toBe('logo.png');
|
||||
expect(res.body.type).toBe('image/png');
|
||||
expect(res.body.size).toBe(30587);
|
||||
});
|
||||
|
||||
// It can *set* cookies from the server()
|
||||
// TODO: it can *get* cookies from the server()
|
||||
it('cookieParser', async () => {
|
||||
const mid = () => cookie('place', '世界').send('Hello 世界');
|
||||
|
||||
const res = await run(mid).post('/', { body: { place: '世界' } });
|
||||
const cookies = res.headers['set-cookie'].join();
|
||||
expect(cookies).toMatch('place=%E4%B8%96%E7%95%8C');
|
||||
});
|
||||
|
||||
// Change the method to the specified one
|
||||
it('method-override through header', async () => {
|
||||
const mid = ctx => {
|
||||
expect(ctx.method).toBe('PUT');
|
||||
expect(ctx.originalMethod).toBe('POST');
|
||||
return 'Hello 世界';
|
||||
};
|
||||
|
||||
const headers = { 'X-HTTP-Method-Override': 'PUT' };
|
||||
const res = await run(mid).post('/', { headers });
|
||||
expect(res.body).toBe('Hello 世界');
|
||||
});
|
||||
|
||||
// Change the method to the specified one
|
||||
it('override-method works with a string', async () => {
|
||||
const mid = ctx => {
|
||||
expect(ctx.method).toBe('PUT');
|
||||
expect(ctx.originalMethod).toBe('POST');
|
||||
return 'Hello 世界';
|
||||
};
|
||||
|
||||
const headers = { 'X-HTTP-Method-Override': 'PUT' };
|
||||
const res = await run({ parser: {
|
||||
method: 'X-HTTP-Method-Override'
|
||||
} }, mid).post('/', { headers });
|
||||
expect(res.body).toBe('Hello 世界');
|
||||
});
|
||||
|
||||
// Change the method to the specified one
|
||||
it('override-method works with an array', async () => {
|
||||
const mid = ctx => {
|
||||
expect(ctx.method).toBe('PUT');
|
||||
expect(ctx.originalMethod).toBe('POST');
|
||||
return 'Hello 世界';
|
||||
};
|
||||
|
||||
const headers = { 'X-HTTP-Method-Override': 'PUT' };
|
||||
const res = await run({ parser: {
|
||||
method: ['X-HTTP-Method-Override']
|
||||
} }, mid).post('/', { headers });
|
||||
expect(res.body).toBe('Hello 世界');
|
||||
});
|
||||
|
||||
// TODO: check more options
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe('Cancel parts through options', () => {
|
||||
|
||||
it('can cancel bodyParser', async () => {
|
||||
const options = { parser: { body: false } };
|
||||
const mid = ctx => {
|
||||
expect(ctx.body).toEqual({});
|
||||
expect(ctx.headers['content-type']).toBe('application/x-www-form-urlencoded');
|
||||
return 'Hello 世界';
|
||||
};
|
||||
|
||||
const res = await run(options, mid).post('/', { form: 'hello=世界' });
|
||||
expect(res.body).toBe('Hello 世界');
|
||||
});
|
||||
|
||||
it('can cancel jsonParser', async () => {
|
||||
const mid = ctx => {
|
||||
expect(ctx.data).toEqual(ctx.req.body);
|
||||
expect(ctx.data).toEqual({});
|
||||
expect(content(ctx)).toBe('application/json');
|
||||
return 'Hello 世界';
|
||||
};
|
||||
|
||||
const res = await run({ parser: { json: false }}, mid).post('/', { body: { hello: '世界' }});
|
||||
expect(res.body).toBe('Hello 世界');
|
||||
});
|
||||
|
||||
// TODO: check all others can be cancelled
|
||||
});
|
63
node_modules/server/plugins/security/index.js
generated
vendored
Normal file
63
node_modules/server/plugins/security/index.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
const modern = require('../../src/modern');
|
||||
const csurf = require('csurf');
|
||||
const helmet = require('helmet');
|
||||
|
||||
module.exports = {
|
||||
name: 'security',
|
||||
options: {
|
||||
csrf: {
|
||||
env: 'SECURITY_CSRF',
|
||||
default: {},
|
||||
type: Object
|
||||
},
|
||||
contentSecurityPolicy: {
|
||||
env: 'SECURITY_CONTENTSECURITYPOLICY'
|
||||
},
|
||||
expectCt: {
|
||||
env: 'SECURITY_EXPECTCT'
|
||||
},
|
||||
dnsPrefetchControl: {
|
||||
env: 'SECURITY_DNSPREFETCHCONTROL'
|
||||
},
|
||||
frameguard: {
|
||||
env: 'SECURITY_FRAMEGUARD'
|
||||
},
|
||||
hidePoweredBy: {
|
||||
env: 'SECURITY_HIDEPOWEREDBY'
|
||||
},
|
||||
hpkp: {
|
||||
env: 'SECURITY_HPKP'
|
||||
},
|
||||
hsts: {
|
||||
env: 'SECURITY_HSTS'
|
||||
},
|
||||
ieNoOpen: {
|
||||
env: 'SECURITY_IENOOPEN'
|
||||
},
|
||||
noCache: {
|
||||
env: 'SECURITY_NOCACHE'
|
||||
},
|
||||
noSniff: {
|
||||
env: 'SECURITY_NOSNIFF'
|
||||
},
|
||||
referrerPolicy: {
|
||||
env: 'SECURITY_REFERRERPOLICY'
|
||||
},
|
||||
xssFilter: {
|
||||
env: 'SECURITY_XSSFILTER'
|
||||
}
|
||||
},
|
||||
before: [
|
||||
ctx => ctx.options.security && ctx.options.security.csrf
|
||||
? modern(csurf(ctx.options.security.csrf))(ctx)
|
||||
: false,
|
||||
ctx => {
|
||||
// Set the csrf for render(): https://expressjs.com/en/api.html#res.locals
|
||||
if (ctx.req.csrfToken) {
|
||||
ctx.csrf = ctx.req.csrfToken();
|
||||
ctx.res.locals.csrf = ctx.csrf;
|
||||
}
|
||||
},
|
||||
ctx => ctx.options.security ? modern(helmet(ctx.options.security))(ctx) : false
|
||||
]
|
||||
};
|
16
node_modules/server/plugins/security/unit.test.js
generated
vendored
Normal file
16
node_modules/server/plugins/security/unit.test.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
const run = require('server/test/run');
|
||||
const { get, post } = require('server/router');
|
||||
|
||||
describe('static plugin', () => {
|
||||
it('csurf', async () => {
|
||||
return await run({ public: 'test' }, [
|
||||
get('/', ctx => ctx.res.locals.csrf),
|
||||
post('/', () => '世界')
|
||||
]).alive(async api => {
|
||||
const csrf = (await api.get('/')).body;
|
||||
expect(csrf).toBeDefined();
|
||||
const res = await api.post('/', { body: { _csrf: csrf }});
|
||||
expect(res.statusCode).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
49
node_modules/server/plugins/session/index.js
generated
vendored
Normal file
49
node_modules/server/plugins/session/index.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
const modern = require('../../src/modern');
|
||||
const server = require('../../server');
|
||||
const session = require('express-session');
|
||||
server.session = session;
|
||||
const RedisStore = require('connect-redis')(server.session);
|
||||
let sessionMiddleware;
|
||||
|
||||
module.exports = {
|
||||
name: 'session',
|
||||
options: {
|
||||
__root: 'secret',
|
||||
resave: {
|
||||
default: false
|
||||
},
|
||||
saveUninitialized: {
|
||||
default: true
|
||||
},
|
||||
cookie: {
|
||||
default: {}
|
||||
},
|
||||
secret: {
|
||||
type: String,
|
||||
inherit: 'secret',
|
||||
env: 'SESSION_SECRET'
|
||||
},
|
||||
store: {
|
||||
env: false
|
||||
},
|
||||
redis: {
|
||||
type: String,
|
||||
inherit: true,
|
||||
env: 'REDIS_URL'
|
||||
}
|
||||
},
|
||||
init: ctx => {
|
||||
if (!ctx.options.session.store && ctx.options.session.redis) {
|
||||
ctx.options.session.store = new RedisStore({
|
||||
url: ctx.options.session.redis
|
||||
});
|
||||
}
|
||||
sessionMiddleware = session(ctx.options.session);
|
||||
},
|
||||
before: ctx => modern(sessionMiddleware)(ctx),
|
||||
launch: ctx => {
|
||||
ctx.io.use(function(socket, next) {
|
||||
sessionMiddleware(socket.request, socket.request.res || {}, next);
|
||||
});
|
||||
}
|
||||
};
|
36
node_modules/server/plugins/session/unit.test.js
generated
vendored
Normal file
36
node_modules/server/plugins/session/unit.test.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
const server = require('server');
|
||||
const run = require('server/test/run');
|
||||
const { get } = require('server/router');
|
||||
const send = require('server/reply/send');
|
||||
|
||||
describe('static plugin', () => {
|
||||
it('can handle sessions', async () => {
|
||||
return run({ public: 'test' }, [
|
||||
get('/a', ctx => {
|
||||
ctx.session.page = 'pageA';
|
||||
return send('');
|
||||
}),
|
||||
get('/b', ctx => send(ctx.session.page))
|
||||
]).alive(async api => {
|
||||
expect((await api.get('/a')).body).toEqual('');
|
||||
expect((await api.get('/b')).body).toEqual('pageA');
|
||||
});
|
||||
});
|
||||
|
||||
it('persists the session', async () => {
|
||||
const mid = ctx => {
|
||||
ctx.session.counter = (ctx.session.counter || 0) + 1;
|
||||
return 'n' + ctx.session.counter;
|
||||
};
|
||||
return run(mid).alive(async api => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const res = await api.get('/');
|
||||
expect(res.body).toBe('n' + (i + 1));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('has the session for creating stores', () => {
|
||||
expect(server.session).toHaveProperty('Store', jasmine.any(Function));
|
||||
});
|
||||
});
|
56
node_modules/server/plugins/socket/index.js
generated
vendored
Normal file
56
node_modules/server/plugins/socket/index.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Create a socket plugin
|
||||
const socketIO = require('socket.io');
|
||||
const extend = require('extend');
|
||||
|
||||
const listeners = {};
|
||||
|
||||
module.exports = {
|
||||
name: 'socket',
|
||||
options: {
|
||||
path: {
|
||||
env: 'SOCKET_PATH'
|
||||
},
|
||||
serveClient: {},
|
||||
adapter: {},
|
||||
origins: {},
|
||||
parser: {},
|
||||
pingTimeout: {},
|
||||
pingInterval: {},
|
||||
upgradeTimeout: {},
|
||||
maxHttpBufferSize: {},
|
||||
allowRequest: {},
|
||||
transports: {},
|
||||
allowUpgrades: {},
|
||||
perMessageDeflate: {},
|
||||
httpCompression: {},
|
||||
cookie: {},
|
||||
cookiePath: {},
|
||||
cookieHttpOnly: {},
|
||||
wsEngine: {}
|
||||
},
|
||||
router: (path, middle) => {
|
||||
listeners[path] = listeners[path] || [];
|
||||
listeners[path].push(middle);
|
||||
},
|
||||
launch: ctx => {
|
||||
if (!ctx.options.socket) return;
|
||||
ctx.io = socketIO(ctx.server, ctx.options.socket);
|
||||
ctx.io.on('connect', socket => {
|
||||
// console.log(socket.client.request.session);
|
||||
for (let path in listeners) {
|
||||
if (path !== 'connect') {
|
||||
listeners[path].forEach(cb => {
|
||||
socket.on(path, data => {
|
||||
cb(extend(socket.client.request, ctx, { path, socket, data }));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if (listeners['connect']) {
|
||||
listeners['connect'].forEach(cb => {
|
||||
cb(extend(socket.client.request, ctx, { path: 'connect', socket }));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
19
node_modules/server/plugins/static/index.js
generated
vendored
Normal file
19
node_modules/server/plugins/static/index.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
const modern = require('../../src/modern');
|
||||
|
||||
module.exports = {
|
||||
name: 'static',
|
||||
options: {
|
||||
__root: 'public',
|
||||
public: {
|
||||
type: String,
|
||||
inherit: 'public',
|
||||
env: false
|
||||
}
|
||||
},
|
||||
init: ctx => {
|
||||
if (!ctx.options.static.public) return;
|
||||
module.exports.before = [
|
||||
modern(ctx.express.static(ctx.options.static.public))
|
||||
];
|
||||
}
|
||||
};
|
45
node_modules/server/plugins/static/unit.test.js
generated
vendored
Normal file
45
node_modules/server/plugins/static/unit.test.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
const run = require('server/test/run');
|
||||
const stat = require('./');
|
||||
|
||||
const storeLog = out => ({ report: { write: log => { out.log = log; } } });
|
||||
|
||||
describe('static plugin', () => {
|
||||
it('exists', () => {
|
||||
expect(stat).toBeDefined();
|
||||
expect(stat.name).toBe('static');
|
||||
expect(stat.options).toBeDefined();
|
||||
});
|
||||
|
||||
it('static', async () => {
|
||||
const res = await run({ public: 'test' }).get('/logo.png');
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.headers['content-type']).toBe('image/png');
|
||||
});
|
||||
|
||||
it('non-existing static', async () => {
|
||||
let out = {};
|
||||
const log = storeLog(out);
|
||||
const res = await run({ public: 'xxxx', log }).get('/non-existing.png');
|
||||
|
||||
expect(res.statusCode).toBe(404);
|
||||
expect(out.log).toMatch(/did not return anything/);
|
||||
});
|
||||
|
||||
it('does not serve if set to false', async () => {
|
||||
let out = {};
|
||||
const log = storeLog(out);
|
||||
const res = await run({ public: false, log }).get('/logo.png');
|
||||
|
||||
expect(res.statusCode).toBe(404);
|
||||
expect(out.log).toMatch(/did not return anything/);
|
||||
});
|
||||
|
||||
it('does not serve if set to empty string', async () => {
|
||||
let out = {};
|
||||
const log = storeLog(out);
|
||||
const res = await run({ public: '', log }).get('/logo.png');
|
||||
|
||||
expect(res.statusCode).toBe(404);
|
||||
expect(out.log).toMatch(/did not return anything/);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user