Comparing version 0.13.1 to 0.13.2
@@ -6,4 +6,4 @@ const assert = require('assert'); | ||
const { handleError } = require('./error'); | ||
const Response = require('./response'); | ||
const RequestBody = require('./body'); | ||
const { getDecoratedRes } = require('./response'); | ||
const { getDecoratedBody } = require('./body'); | ||
@@ -145,3 +145,3 @@ function pathToRegexp(path){ | ||
const res = input.res = new Response(input, reqInfo); | ||
const res = input.res = getDecoratedRes(input, reqInfo); | ||
@@ -153,3 +153,3 @@ const handler = matchRoute.call(this, method, path, params); | ||
input.body = new RequestBody(input); | ||
input.body = getDecoratedBody(input); | ||
if(app._autoParseBody && !input.websocket) | ||
@@ -156,0 +156,0 @@ input.body = await input.body.parse(); |
@@ -8,6 +8,6 @@ | ||
const fbto = setTimeout(() => { | ||
this.stream.emit('error', new Error('Client took too long before starting to send request body'), 408) | ||
this.emit('error', new Error('Client took too long before starting to send request body'), 408) | ||
}, 3000); | ||
this.stream.on('data', chunk => { | ||
this.on('data', chunk => { | ||
clearTimeout(fbto); | ||
@@ -17,13 +17,13 @@ buffer.push(chunk); | ||
this.stream.on('close', () => { | ||
this.on('close', () => { | ||
buffer = null; | ||
this.stream.removeAllListeners(); | ||
this.removeAllListeners(); | ||
}); | ||
this.stream.on('aborted', () => | ||
this.stream.emit('error', new Error('Request aborted by the client'))); | ||
this.on('aborted', () => | ||
this.emit('error', new Error('Request aborted by the client'))); | ||
return new Promise((resolve, reject) => { | ||
this.stream.on('end', () => { | ||
this.on('end', () => { | ||
clearTimeout(fbto); | ||
@@ -34,3 +34,3 @@ !complete && resolve(Buffer.concat(buffer)); | ||
this.stream.on('error', (err, code) => { | ||
this.on('error', (err, code) => { | ||
!complete && reject(this.res.error(code ?? 400, err.message)); | ||
@@ -59,16 +59,7 @@ complete = true; | ||
module.exports = class RequestBody { | ||
const decorator = { | ||
constructor({ res, headers, body }){ | ||
const t = getDataTypeFromContentType(headers['content-type']); | ||
this.type = t.type; | ||
this.charset = t.charset; | ||
this.stream = body; | ||
this.res = res; | ||
this.length = Number(headers['content-length']); | ||
} | ||
raw(){ | ||
return read.call(this); | ||
} | ||
}, | ||
@@ -78,3 +69,3 @@ text(){ | ||
return read.call(this, raw => raw.toString(this.charset)); | ||
} | ||
}, | ||
@@ -84,3 +75,3 @@ json(){ | ||
return read.call(this, raw => JSON.parse(raw.toString(this.charset))); | ||
} | ||
}, | ||
@@ -91,3 +82,3 @@ urlencoded(){ | ||
Object.fromEntries(new URLSearchParams(raw.toString(this.charset)).entries())); | ||
} | ||
}, | ||
@@ -98,2 +89,15 @@ parse(){ | ||
}; | ||
module.exports.getDecoratedBody = function({ res, headers, body }) { | ||
const t = getDataTypeFromContentType(headers['content-type']); | ||
body.type = t.type; | ||
body.charset = t.charset; | ||
body.res = res; | ||
body.length = Number(headers['content-length']); | ||
Object.assign(body, decorator); | ||
return body; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Server } from 'http' | ||
import { Server, ServerResponse, IncomingMessage } from 'http' | ||
import WebSocket from 'ws' | ||
@@ -49,3 +49,3 @@ | ||
class Response { | ||
class Response extends ServerResponse { | ||
@@ -99,4 +99,3 @@ /** In case `cond` is falsy, throws HTTP error with `status` and `message` as body printf-formated with `args` */ | ||
class RequestBody { | ||
stream: Request | ||
class RequestBody extends IncomingMessage { | ||
raw(): Promise<Buffer | unknown> | ||
@@ -223,3 +222,6 @@ text(): Promise<string> | ||
/** Run a given nodecaf app handling uncaught errors and node process signals */ | ||
/** | ||
* Run a given nodecaf app handling uncaught errors and node process signals | ||
* @deprecated This function will be dropped on `v0.14.0`. Use `app.run()` instead. | ||
*/ | ||
static run(opts: Nodecaf.RunOptions): void | ||
@@ -263,3 +265,3 @@ | ||
*/ | ||
setup(conf: Record<string, unknown> | string): void | ||
setup(...conf: Record<string, unknown> | string): void | ||
@@ -280,4 +282,10 @@ /** | ||
}> | ||
/** | ||
* Run the app handling uncaught errors and node process signals. | ||
*/ | ||
run(opts: Nodecaf.RunOptions): Promise<Nodecaf> | ||
} | ||
export = Nodecaf |
@@ -75,4 +75,4 @@ const | ||
setup(objectOrPath = {}){ | ||
this.conf = confort(this.conf, objectOrPath); | ||
setup(...objectOrPath){ | ||
this.conf = confort(this.conf, ...objectOrPath); | ||
this._cors = cors(this.conf.cors); | ||
@@ -152,4 +152,4 @@ | ||
if(input.body && !(input.body instanceof Readable)){ | ||
const ob = input.body; | ||
if(!(input.body instanceof Readable)){ | ||
const ob = input.body ?? ''; | ||
const oh = input.headers ?? {}; | ||
@@ -198,9 +198,41 @@ input = { ...input }; | ||
async run(opts = {}){ | ||
this.setup(...[].concat(opts.conf)); | ||
/* istanbul ignore next */ | ||
const term = () => { | ||
this.stop(); | ||
setTimeout(() => process.exit(0), 2000); | ||
} | ||
/* istanbul ignore next */ | ||
const die = err => { | ||
this.log.fatal({ err, type: 'crash' }); | ||
process.exit(1); | ||
} | ||
process.on('SIGINT', term); | ||
process.on('SIGTERM', term); | ||
process.on('uncaughtException', die); | ||
process.on('unhandledRejection', die); | ||
await this.start(); | ||
return this; | ||
} | ||
} | ||
http.METHODS.forEach(m => module.exports[m.toLowerCase()] = function(path, handler, opts){ | ||
const METHODS = [ | ||
'get', 'post', 'head', 'delete', 'put', 'patch', 'options', 'connect', 'trace' | ||
]; | ||
METHODS.forEach(m => module.exports[m] = function(path, handler, opts){ | ||
return { ...opts, method: m, path, handler }; | ||
}); | ||
// Needed because it's not possible to call a function named 'delete' | ||
module.exports.del = (path, handler, opts) => ({ ...opts, method: 'delete', path, handler }); | ||
module.exports.all = handler => ({ all: true, handler }); | ||
module.exports.run = require('./run'); |
@@ -23,22 +23,4 @@ const { sign } = require('cookie-signature'); | ||
module.exports = class Response { | ||
const decorator = { | ||
constructor(input, reqInfo){ | ||
this.reqInfo = reqInfo; | ||
this.resStream = input.res; | ||
this.input = input; | ||
this.ended = new Promise((resolve, reject) => { | ||
this.resolve = resolve; | ||
this.reject = reject; | ||
}); | ||
this.headers = {}; | ||
this.statusCode = 200; | ||
for(const name in ASSERTS) | ||
this[name] = this.assert.bind(this, ASSERTS[name]); | ||
} | ||
write(chunk){ | ||
this.resStream.write(chunk); | ||
} | ||
end(body){ | ||
@@ -50,3 +32,3 @@ | ||
body && this.write(body); | ||
this.resStream.end(); | ||
this._realEnd(); | ||
@@ -65,5 +47,5 @@ this.input.log.debug({ | ||
headers: this.headers, | ||
body: this.resStream | ||
body: this | ||
}); | ||
} | ||
}, | ||
@@ -92,3 +74,3 @@ // Not necessarily an APP error, but a client Error | ||
return new HTTPError(status, message, type); | ||
} | ||
}, | ||
@@ -99,9 +81,9 @@ assert(status, cond, message, ...args){ | ||
throw this.error(status, message, ...args); | ||
} | ||
}, | ||
set(k, v){ | ||
this.resStream.setHeader?.(k, v); | ||
this.setHeader?.(k, v); | ||
this.headers[k] = v; | ||
return this; | ||
} | ||
}, | ||
@@ -114,9 +96,8 @@ append(k, v){ | ||
return this.set(k, v); | ||
} | ||
}, | ||
status(s){ | ||
this.resStream.statusCode = s; | ||
this.statusCode = s; | ||
return this; | ||
} | ||
}, | ||
@@ -126,3 +107,3 @@ type(ct){ | ||
return this; | ||
} | ||
}, | ||
@@ -133,3 +114,3 @@ json(data){ | ||
return this; | ||
} | ||
}, | ||
@@ -140,3 +121,3 @@ text(data){ | ||
return this; | ||
} | ||
}, | ||
@@ -147,3 +128,3 @@ clearCookie(name, opts) { | ||
return this.cookie(name, '', opts); | ||
} | ||
}, | ||
@@ -171,3 +152,24 @@ cookie(name, value, opts = {}) { | ||
} | ||
}; | ||
module.exports.getDecoratedRes = function (input, reqInfo) { | ||
const res = input.res; | ||
res.reqInfo = reqInfo; | ||
res.input = input; | ||
res.ended = new Promise((resolve, reject) => { | ||
res.resolve = resolve; | ||
res.reject = reject; | ||
}); | ||
res.headers = {}; | ||
res.statusCode = 200; | ||
res._realEnd = res.end; | ||
Object.assign(res, decorator); | ||
for(const name in ASSERTS) | ||
res[name] = res.assert.bind(res, ASSERTS[name]); | ||
return res; | ||
} | ||
@@ -174,0 +176,0 @@ |
@@ -11,2 +11,4 @@ | ||
app.log.warn('`Nodecaf.run()` is deprecated. This option will be dropped on `v0.14.0`. Use `app.run()` instead.'); | ||
const confPath = opts.conf || []; | ||
@@ -13,0 +15,0 @@ const confs = Array.isArray(confPath) ? confPath : [confPath]; |
{ | ||
"name": "nodecaf", | ||
"version": "0.13.1", | ||
"version": "0.13.2", | ||
"description": "Nodecaf is a light framework for developing RESTful Apps in a quick and convenient manner.", | ||
@@ -41,3 +41,3 @@ "main": "lib/main.js", | ||
"dependencies": { | ||
"confort": "^0.2.0", | ||
"confort": "^0.2.1", | ||
"cookie": "^0.5.0", | ||
@@ -44,0 +44,0 @@ "cookie-signature": "^1.1.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
53461
927
Updatedconfort@^0.2.1