Comparing version 0.2.5 to 1.0.0
@@ -1,171 +0,5 @@ | ||
import { Readable } from 'stream'; | ||
import { Url } from 'url'; | ||
import { EventEmitter } from 'events'; | ||
import { BaseError } from 'make-error-cause'; | ||
/** | ||
* Valid body payloads. | ||
*/ | ||
export declare type Body = undefined | null | string | Buffer | Readable | {}; | ||
/** | ||
* Raw HTTP header formats allowed. | ||
*/ | ||
export declare type HeaderFormats = Headers | HeadersObject | string[] | null | undefined; | ||
/** | ||
* Create a `HttpError` instance. | ||
*/ | ||
export default class HttpError extends BaseError { | ||
code: string; | ||
status: number; | ||
request: Request; | ||
headers?: HeadersObject; | ||
name: string; | ||
constructor(message: string, code: string, status: number, request: Request, cause?: Error, headers?: HeadersObject); | ||
} | ||
/** | ||
* Raw headers object. | ||
*/ | ||
export interface HeadersObject { | ||
[key: string]: string | string[]; | ||
} | ||
/** | ||
* Header container class. | ||
*/ | ||
export declare class Headers { | ||
raw: string[]; | ||
constructor(headers: HeaderFormats); | ||
object(keepHeaderCase?: boolean): HeadersObject; | ||
object(obj: HeadersObject | null): void; | ||
set(name: string, value?: string | number | string[]): this; | ||
append(name: string, value?: null | string | number | string[]): this; | ||
get(name: string): string | undefined; | ||
getAll(name: string): string[]; | ||
has(name: string): boolean; | ||
delete(name: string): this; | ||
} | ||
/** | ||
* Base request/response options. | ||
*/ | ||
export interface CommonOptions { | ||
headers?: HeaderFormats; | ||
trailers?: HeaderFormats; | ||
events?: EventEmitter; | ||
body?: Body; | ||
} | ||
/** | ||
* Create a base class for requests and responses. | ||
*/ | ||
export declare class Common implements CommonOptions { | ||
events: EventEmitter; | ||
private _body; | ||
private _bodyUsed; | ||
private _bodyBuffered; | ||
private _headers; | ||
private _trailers; | ||
private _started; | ||
private _finished; | ||
private _bytesTransferred; | ||
constructor({trailers, headers, events, body}?: CommonOptions); | ||
finished: boolean; | ||
started: boolean; | ||
bytesTransferred: number; | ||
headers: Headers; | ||
trailers: Headers; | ||
body: Body; | ||
readonly bodyUsed: boolean; | ||
readonly bodyBuffered: boolean; | ||
type: string | undefined; | ||
length: number | undefined; | ||
buffer(maxBufferSize?: number): Promise<Buffer | undefined>; | ||
stream(): Readable; | ||
text(maxBufferSize?: number): Promise<string | undefined>; | ||
} | ||
/** | ||
* HTTP request connection information. | ||
*/ | ||
export interface Connection { | ||
remoteAddress?: string; | ||
remotePort?: number; | ||
localAddress?: string; | ||
localPort?: number; | ||
encrypted?: boolean; | ||
} | ||
/** | ||
* HTTP request class options. | ||
*/ | ||
export interface RequestOptions extends CommonOptions { | ||
url: string; | ||
method?: string; | ||
connection?: Connection; | ||
} | ||
/** | ||
* The HTTP request class. | ||
*/ | ||
export declare class Request extends Common implements RequestOptions { | ||
aborted: boolean; | ||
originalUrl: string; | ||
connection: Connection; | ||
private _Url; | ||
private _url; | ||
private _method; | ||
constructor(options: RequestOptions); | ||
url: string; | ||
readonly Url: Url; | ||
method: string; | ||
error(message: string, code: string, status?: number, original?: Error, headers?: HeadersObject): HttpError; | ||
abort(): boolean; | ||
toJSON(): { | ||
url: string; | ||
method: string; | ||
body: Body; | ||
headers: HeadersObject; | ||
trailers: HeadersObject; | ||
started: boolean; | ||
finished: boolean; | ||
bytesTransferred: number; | ||
}; | ||
inspect(): { | ||
url: string; | ||
method: string; | ||
body: Body; | ||
headers: HeadersObject; | ||
trailers: HeadersObject; | ||
started: boolean; | ||
finished: boolean; | ||
bytesTransferred: number; | ||
}; | ||
} | ||
/** | ||
* HTTP response class options. | ||
*/ | ||
export interface ResponseOptions extends CommonOptions { | ||
status?: number; | ||
statusText?: string; | ||
} | ||
/** | ||
* The HTTP response class. | ||
*/ | ||
export declare class Response extends Common implements ResponseOptions { | ||
status: number | undefined; | ||
statusText: string | undefined; | ||
constructor(options?: ResponseOptions); | ||
toJSON(): { | ||
status: number | undefined; | ||
statusText: string | undefined; | ||
body: Body; | ||
headers: HeadersObject; | ||
trailers: HeadersObject; | ||
started: boolean; | ||
finished: boolean; | ||
bytesTransferred: number; | ||
}; | ||
inspect(): { | ||
status: number | undefined; | ||
statusText: string | undefined; | ||
body: Body; | ||
headers: HeadersObject; | ||
trailers: HeadersObject; | ||
started: boolean; | ||
finished: boolean; | ||
bytesTransferred: number; | ||
}; | ||
} | ||
export * from './headers'; | ||
export * from './body'; | ||
export * from './base'; | ||
export * from './request'; | ||
export * from './response'; |
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var stream_1 = require("stream"); | ||
var url_1 = require("url"); | ||
var events_1 = require("events"); | ||
var make_error_cause_1 = require("make-error-cause"); | ||
/** | ||
* Quick splice. | ||
*/ | ||
function splice(arr, start, count) { | ||
for (var i = start; i < arr.length - count; i++) { | ||
arr[i] = arr[i + count]; | ||
} | ||
arr.length -= count; | ||
} | ||
/** | ||
* Consistently lower case a header name. | ||
*/ | ||
function lowerHeader(key) { | ||
var lower = key.toLowerCase(); | ||
if (lower === 'referrer') { | ||
return 'referer'; | ||
} | ||
return lower; | ||
} | ||
/** | ||
* Concat two header values together. | ||
*/ | ||
function join(a, b) { | ||
if (a === undefined) { | ||
return b; | ||
} | ||
return Array.isArray(a) ? a.concat(b) : [a, b]; | ||
} | ||
/** | ||
* Extract the content type from a header string. | ||
*/ | ||
function parseType(str) { | ||
var index = str.indexOf(';'); | ||
return index === -1 ? str.trim() : str.slice(0, index).trim(); | ||
} | ||
/** | ||
* Create a `HttpError` instance. | ||
*/ | ||
var HttpError = (function (_super) { | ||
__extends(HttpError, _super); | ||
function HttpError(message, code, status, request, cause, headers) { | ||
var _this = _super.call(this, message, cause) || this; | ||
_this.name = 'HttpError'; | ||
_this.code = code; | ||
_this.status = status; | ||
_this.request = request; | ||
_this.headers = headers; | ||
return _this; | ||
} | ||
return HttpError; | ||
}(make_error_cause_1.BaseError)); | ||
exports.default = HttpError; | ||
/** | ||
* Header container class. | ||
*/ | ||
var Headers = (function () { | ||
function Headers(headers) { | ||
this.raw = []; | ||
if (headers instanceof Headers) { | ||
this.raw = headers.raw; | ||
} | ||
else if (Array.isArray(headers)) { | ||
if (headers.length % 2 === 1) { | ||
throw new TypeError("Expected raw headers length to be even, got " + headers.length); | ||
} | ||
this.raw = headers.slice(0); | ||
} | ||
else if (headers) { | ||
this.object(headers); | ||
} | ||
} | ||
Headers.prototype.object = function (obj) { | ||
if (typeof obj === 'object') { | ||
splice(this.raw, 0, this.raw.length); | ||
if (obj) { | ||
for (var _i = 0, _a = Object.keys(obj); _i < _a.length; _i++) { | ||
var key = _a[_i]; | ||
this.append(key, obj[key]); | ||
} | ||
} | ||
return; | ||
} | ||
var headers = Object.create(null); | ||
for (var i = 0; i < this.raw.length; i += 2) { | ||
var key = obj === true ? this.raw[i] : lowerHeader(this.raw[i]); | ||
var value = join(headers[key], this.raw[i + 1]); | ||
headers[key] = value; | ||
} | ||
return headers; | ||
}; | ||
Headers.prototype.set = function (name, value) { | ||
this.delete(name); | ||
this.append(name, value); | ||
return this; | ||
}; | ||
Headers.prototype.append = function (name, value) { | ||
if (Array.isArray(value)) { | ||
for (var _i = 0, value_1 = value; _i < value_1.length; _i++) { | ||
var item = value_1[_i]; | ||
this.raw.push(name, String(item)); | ||
} | ||
} | ||
else if (value != null) { | ||
this.raw.push(name, String(value)); | ||
} | ||
return this; | ||
}; | ||
Headers.prototype.get = function (name) { | ||
var lowered = lowerHeader(name); | ||
for (var i = 0; i < this.raw.length; i += 2) { | ||
if (lowerHeader(this.raw[i]) === lowered) { | ||
return this.raw[i + 1]; | ||
} | ||
} | ||
return undefined; | ||
}; | ||
Headers.prototype.getAll = function (name) { | ||
var lowered = lowerHeader(name); | ||
var result = []; | ||
for (var i = 0; i < this.raw.length; i += 2) { | ||
if (lowerHeader(this.raw[i]) === lowered) { | ||
result.push(this.raw[i + 1]); | ||
} | ||
} | ||
return result; | ||
}; | ||
Headers.prototype.has = function (name) { | ||
var lowered = lowerHeader(name); | ||
for (var i = 0; i < this.raw.length; i += 2) { | ||
if (lowerHeader(this.raw[i]) === lowered) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
Headers.prototype.delete = function (name) { | ||
var lowered = lowerHeader(name); | ||
for (var i = 0; i < this.raw.length; i += 2) { | ||
if (lowerHeader(this.raw[i]) === lowered) { | ||
splice(this.raw, i, 2); | ||
} | ||
} | ||
return this; | ||
}; | ||
return Headers; | ||
}()); | ||
exports.Headers = Headers; | ||
/** | ||
* Create a base class for requests and responses. | ||
*/ | ||
var Common = (function () { | ||
function Common(_a) { | ||
var _b = _a === void 0 ? {} : _a, trailers = _b.trailers, headers = _b.headers, events = _b.events, body = _b.body; | ||
this._bodyUsed = true; | ||
this._bodyBuffered = true; | ||
this._started = false; | ||
this._finished = false; | ||
this._bytesTransferred = 0; | ||
this.events = events || new events_1.EventEmitter(); | ||
this.headers = new Headers(headers); | ||
this.trailers = new Headers(trailers); | ||
this.body = body; | ||
} | ||
Object.defineProperty(Common.prototype, "finished", { | ||
get: function () { | ||
return this._finished; | ||
}, | ||
set: function (finished) { | ||
if (!this._finished && finished) { | ||
this._finished = true; | ||
this.events.emit('finished'); | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "started", { | ||
get: function () { | ||
return this._started; | ||
}, | ||
set: function (started) { | ||
if (!this._started && started) { | ||
this._started = true; | ||
this.events.emit('started'); | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "bytesTransferred", { | ||
get: function () { | ||
return this._bytesTransferred; | ||
}, | ||
set: function (bytes) { | ||
if (bytes > this._bytesTransferred) { | ||
this._bytesTransferred = bytes; | ||
this.events.emit('progress', this); | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "headers", { | ||
get: function () { | ||
return this._headers; | ||
}, | ||
set: function (headers) { | ||
this._headers = headers; | ||
this.events.emit('headers', this._headers); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "trailers", { | ||
get: function () { | ||
return this._trailers; | ||
}, | ||
set: function (trailers) { | ||
this._trailers = trailers; | ||
this.events.emit('trailers', this._trailers); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "body", { | ||
get: function () { | ||
return this._body; | ||
}, | ||
set: function (body) { | ||
this._bodyUsed = false; | ||
if (body === undefined || body === null) { | ||
this._body = undefined; | ||
this._bodyBuffered = true; | ||
this.headers.delete('Content-Type'); | ||
this.headers.delete('Content-Length'); | ||
this.headers.delete('Content-Encoding'); | ||
return; | ||
} | ||
var setType = this.headers.get('Content-Type') === undefined; | ||
var setLength = this.headers.get('Content-Length') === undefined; | ||
if (typeof body === 'string') { | ||
if (setType) | ||
this.type = 'text/plain'; | ||
if (setLength) | ||
this.length = Buffer.byteLength(body); | ||
this._body = body; | ||
this._bodyBuffered = true; | ||
return; | ||
} | ||
if (Buffer.isBuffer(body)) { | ||
if (setType) | ||
this.type = 'application/octet-stream'; | ||
if (setLength) | ||
this.length = body.length; | ||
this._body = body; | ||
this._bodyBuffered = true; | ||
return; | ||
} | ||
if (isStream(body)) { | ||
if (setType) | ||
this.type = 'application/octet-stream'; | ||
this._body = body; | ||
this._bodyBuffered = false; | ||
return; | ||
} | ||
if (isBasicObject(body)) { | ||
var str = JSON.stringify(body); | ||
if (setType) | ||
this.type = 'application/json'; | ||
if (setLength) | ||
this.length = Buffer.byteLength(str); | ||
this._body = str; | ||
this._bodyBuffered = true; | ||
return; | ||
} | ||
throw new TypeError("Unknown body: " + body); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "bodyUsed", { | ||
get: function () { | ||
return this._bodyUsed; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "bodyBuffered", { | ||
get: function () { | ||
return this._bodyBuffered; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "type", { | ||
get: function () { | ||
var header = this.headers.get('Content-Type'); | ||
return header === undefined ? undefined : parseType(header); | ||
}, | ||
set: function (type) { | ||
this.headers.set('Content-Type', type); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Common.prototype, "length", { | ||
get: function () { | ||
var len = this.headers.get('Content-Length'); | ||
return len === undefined ? undefined : Number(len); | ||
}, | ||
set: function (length) { | ||
this.headers.set('Content-Length', length); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Common.prototype.buffer = function (maxBufferSize) { | ||
if (maxBufferSize === void 0) { maxBufferSize = 1000 * 1000; } | ||
if (this.bodyUsed) { | ||
return Promise.reject(new TypeError('Already read')); | ||
} | ||
var body; | ||
if (this._body === undefined || Buffer.isBuffer(this._body)) { | ||
body = Promise.resolve(this._body); | ||
} | ||
else if (typeof this._body === 'string') { | ||
body = Promise.resolve(new Buffer(this._body)); | ||
} | ||
else if (isStream(this._body)) { | ||
var stream_2 = this._body; | ||
var buf_1 = []; | ||
var length_1 = 0; | ||
body = new Promise(function (resolve, reject) { | ||
stream_2.on('error', reject); | ||
stream_2.on('data', function (chunk) { | ||
if (length_1 > maxBufferSize) { | ||
return; | ||
} | ||
length_1 += chunk.length; | ||
if (length_1 <= maxBufferSize) { | ||
buf_1.push(chunk); | ||
} | ||
}); | ||
stream_2.on('end', function () { | ||
if (length_1 > maxBufferSize) { | ||
return reject(new TypeError('Stream exceeded max buffer length')); | ||
} | ||
return resolve(Buffer.concat(buf_1)); | ||
}); | ||
}); | ||
} | ||
else { | ||
body = Promise.resolve(new Buffer(JSON.stringify(this._body))); | ||
} | ||
this._body = undefined; | ||
this._bodyUsed = true; | ||
return body; | ||
}; | ||
Common.prototype.stream = function () { | ||
if (this.bodyUsed) { | ||
throw new TypeError('Already read'); | ||
} | ||
var body; | ||
if (this._body === undefined) { | ||
body = new stream_1.Readable({ read: function () { this.push(null); } }); | ||
} | ||
else if (typeof this._body === 'string' || Buffer.isBuffer(this._body)) { | ||
var o_1 = this._body; | ||
body = new stream_1.Readable({ | ||
read: function () { | ||
this.push(o_1); | ||
o_1 = null; | ||
} | ||
}); | ||
} | ||
else if (isStream(this._body)) { | ||
body = this._body; | ||
} | ||
else { | ||
var o_2 = JSON.stringify(this._body); | ||
body = new stream_1.Readable({ | ||
read: function () { | ||
this.push(o_2); | ||
o_2 = null; | ||
} | ||
}); | ||
} | ||
this._body = undefined; | ||
this._bodyUsed = true; | ||
return body; | ||
}; | ||
Common.prototype.text = function (maxBufferSize) { | ||
if (this.bodyUsed) { | ||
return Promise.reject(new TypeError('Already read')); | ||
} | ||
if (typeof this._body === 'string') { | ||
var body = this._body; | ||
this._body = undefined; | ||
this._bodyUsed = true; | ||
return Promise.resolve(body); | ||
} | ||
return this.buffer(maxBufferSize).then(function (x) { return x ? x.toString('utf8') : undefined; }); | ||
}; | ||
return Common; | ||
}()); | ||
exports.Common = Common; | ||
/** | ||
* The HTTP request class. | ||
*/ | ||
var Request = (function (_super) { | ||
__extends(Request, _super); | ||
function Request(options) { | ||
var _this = _super.call(this, options) || this; | ||
_this.aborted = false; | ||
_this.url = options.url; | ||
_this.method = options.method || 'GET'; | ||
_this.originalUrl = _this.url; | ||
_this.connection = options.connection || {}; | ||
return _this; | ||
} | ||
Object.defineProperty(Request.prototype, "url", { | ||
get: function () { | ||
return this._url; | ||
}, | ||
set: function (url) { | ||
this._url = url || ''; | ||
this._Url = undefined; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Request.prototype, "Url", { | ||
get: function () { | ||
return this._Url || (this._Url = url_1.parse(this._url, false, true)); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Request.prototype, "method", { | ||
get: function () { | ||
return this._method; | ||
}, | ||
set: function (method) { | ||
this._method = method.toUpperCase(); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Request.prototype.error = function (message, code, status, original, headers) { | ||
if (status === void 0) { status = 500; } | ||
return new HttpError(message, code, status, this, original, headers); | ||
}; | ||
Request.prototype.abort = function () { | ||
var abort = !this.aborted && !this.finished; | ||
if (abort) { | ||
this.aborted = true; | ||
this.events.emit('abort', this.error('Request aborted', 'EABORT', 444)); | ||
} | ||
return abort; | ||
}; | ||
Request.prototype.toJSON = function () { | ||
return { | ||
url: this.url, | ||
method: this.method, | ||
body: this.body, | ||
headers: this.headers.object(), | ||
trailers: this.trailers.object(), | ||
started: this.started, | ||
finished: this.finished, | ||
bytesTransferred: this.bytesTransferred | ||
}; | ||
}; | ||
Request.prototype.inspect = function () { | ||
return this.toJSON(); | ||
}; | ||
return Request; | ||
}(Common)); | ||
exports.Request = Request; | ||
/** | ||
* The HTTP response class. | ||
*/ | ||
var Response = (function (_super) { | ||
__extends(Response, _super); | ||
function Response(options) { | ||
if (options === void 0) { options = {}; } | ||
var _this = _super.call(this, options) || this; | ||
_this.status = options.status; | ||
_this.statusText = options.statusText; | ||
return _this; | ||
} | ||
Response.prototype.toJSON = function () { | ||
return { | ||
status: this.status, | ||
statusText: this.statusText, | ||
body: this.body, | ||
headers: this.headers.object(), | ||
trailers: this.trailers.object(), | ||
started: this.started, | ||
finished: this.finished, | ||
bytesTransferred: this.bytesTransferred | ||
}; | ||
}; | ||
Response.prototype.inspect = function () { | ||
return this.toJSON(); | ||
}; | ||
return Response; | ||
}(Common)); | ||
exports.Response = Response; | ||
/** | ||
* Check if a stream is readable. | ||
*/ | ||
function isStream(stream) { | ||
return stream !== null && typeof stream === 'object' && typeof stream.pipe === 'function'; | ||
} | ||
/** | ||
* Check if an object is plain. | ||
*/ | ||
function isBasicObject(obj) { | ||
if (typeof obj !== 'object') { | ||
return false; | ||
} | ||
var proto = Object.getPrototypeOf(obj); | ||
return proto === null || proto === Object.prototype || proto === Array.prototype; | ||
} | ||
// Standard interfaces. | ||
__export(require("./headers")); | ||
__export(require("./body")); | ||
__export(require("./base")); | ||
__export(require("./request")); | ||
__export(require("./response")); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "servie", | ||
"version": "0.2.5", | ||
"version": "1.0.0", | ||
"description": "Standard HTTP interfaces", | ||
@@ -9,12 +9,14 @@ "main": "dist/index.js", | ||
"dist/", | ||
"typings.json", | ||
"LICENSE", | ||
"logo.svg" | ||
], | ||
"browser": { | ||
"./dist/body/node": "./dist/body/browser" | ||
}, | ||
"scripts": { | ||
"lint": "tslint \"src/**/*.ts\" --type-check --project tsconfig.json", | ||
"lint": "tslint \"src/**/*.ts\" --project tsconfig.json", | ||
"build": "rm -rf dist/ && tsc", | ||
"specs": "jest --coverage", | ||
"test": "npm run -s lint && npm run -s build && npm run -s specs", | ||
"prepublish": "typings install && npm run build" | ||
"prepublish": "npm run build" | ||
}, | ||
@@ -44,13 +46,32 @@ "repository": { | ||
"homepage": "https://github.com/serviejs/servie", | ||
"jest": { | ||
"roots": [ | ||
"<rootDir>/src/" | ||
], | ||
"transform": { | ||
"\\.tsx?$": "ts-jest" | ||
}, | ||
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json", | ||
"node" | ||
] | ||
}, | ||
"devDependencies": { | ||
"jest": "^19.0.0", | ||
"rimraf": "^2.5.4", | ||
"tslint": "^5.0.0", | ||
"tslint-config-standard": "^5.0.2", | ||
"typescript": "^2.2.1", | ||
"typings": "^2.1.0" | ||
"@types/jest": "^22.2.2", | ||
"@types/node": "^9.6.0", | ||
"jest": "^22.4.3", | ||
"rimraf": "^2.6.2", | ||
"ts-jest": "^22.4.2", | ||
"tslint": "^5.9.1", | ||
"tslint-config-standard": "^7.0.0", | ||
"typescript": "^2.8.1" | ||
}, | ||
"dependencies": { | ||
"make-error-cause": "^1.2.2" | ||
"byte-length": "^1.0.2" | ||
} | ||
} |
133
README.md
@@ -8,3 +8,3 @@ # ![Servie](https://cdn.rawgit.com/serviejs/servie/master/logo.svg) | ||
> **Servie** provides standard, framework-agnostic HTTP interfaces for servers and clients. | ||
> Standard, framework-agnostic HTTP interfaces for JavaScript servers and clients. | ||
@@ -23,4 +23,3 @@ ## Installation | ||
* [`busboy`](https://www.npmjs.com/package/busboy) A streaming parser for HTML form data | ||
* [`qs`](https://github.com/ljharb/qs) and [`querystring`](https://nodejs.org/api/querystring.html) Parse the HTTP query string to an object | ||
* [`consolidate`](https://github.com/tj/consolidate.js) Template rendering | ||
* [`qs`](https://github.com/ljharb/qs) and [`querystring`](https://nodejs.org/api/querystring.html) Parse HTTP query string to object | ||
* [`get-body`](https://github.com/serviejs/get-body) General body parser for forms, JSON and text | ||
@@ -35,4 +34,7 @@ * [`servie-cors`](https://github.com/serviejs/servie-cors) CORS middleware for Servie | ||
* [`servie-finalhandler`](https://github.com/serviejs/servie-finalhandler) Standard final handler for transport layers | ||
* [`http-errors`](https://github.com/jshttp/http-errors) Create HTTP errors | ||
* [`boom`](https://github.com/hapijs/boom) HTTP-friendly error objects | ||
* [`consolidate`](https://github.com/tj/consolidate.js) Template rendering | ||
### `Common` | ||
### `Servie` | ||
@@ -42,3 +44,3 @@ > Base HTTP class for common request and response logic. | ||
```ts | ||
import { Common } from 'servie' | ||
import { Servie } from 'servie' | ||
``` | ||
@@ -48,17 +50,13 @@ | ||
* `headers?` HTTP headers (`Headers | HeadersObject | string[]`) | ||
* `trailers?` HTTP trailers (`Headers | HeadersObject | string[]`) | ||
* `events?` An event emitter object (`EventEmitter`) | ||
* `body?` Allowed HTTP bodies (`string | Buffer | Readable | object`) | ||
* `events?` An instance of `EventEmitter` | ||
* `headers?` An instance of `Headers` | ||
* `trailers?` An instance of `Headers` | ||
* `body?` An instance of `Body` | ||
#### Properties | ||
* `events` An event emitter for listening to the request and response lifecycles | ||
* `events` An event emitter for listening to the request and response lifecycle | ||
* `headers` The headers as a `Headers` instance | ||
* `trailers` The trailers as a `Headers` instance | ||
* `body` The request or response payload | ||
* `bodyUsed` A boolean indicating whether the body has been read | ||
* `bodyBuffered` A boolean indicating whether the body is buffered (e.g. string or buffer, not a stream) | ||
* `type` A shorthand property for reading and writing the `Content-Type` header | ||
* `length` A shorthand property for reading and writing `Content-Length` as a number | ||
* `started` Boolean indicating if a request/response has started | ||
@@ -70,5 +68,3 @@ * `finished` Boolean indicating if a request/response has finished | ||
* `buffer(maxBufferSize): Promise<Buffer>` Read the body into a `Buffer` object | ||
* `text(maxBufferSize): Promise<string>` Read the body as a `string` | ||
* `stream(): Readable` Read the body as a `Readable` stream | ||
* `getHeaders()` Returns the combined `Request` and `Body` headers (`Headers`) | ||
@@ -81,7 +77,7 @@ #### Events | ||
* `finished` Emitted when `finished === true` | ||
* `progress` Emitted when `bytesTransferred` is incremented | ||
* `progress` Emitted when `bytesTransferred` increments | ||
### `Request` | ||
> HTTP class for encapsulating a `Request`, extends `Common`. | ||
> HTTP class for encapsulating a `Request`, extends `Servie`. | ||
@@ -101,3 +97,3 @@ ```ts | ||
> Extends `Common` options. | ||
> Extends `Servie` options. | ||
@@ -110,21 +106,21 @@ * `url` The HTTP request url (`string`) | ||
* `url` The HTTP request url (`string`) | ||
* `method` The HTTP request method upper-cased (`string`) | ||
* `Url` The HTTP request url as a read-only parsed object (`object`) | ||
* `connection` Connection information (`{}`) | ||
* `url` Requested url (`string`) | ||
* `method` Requested method (`string`) | ||
* `Url` Request url parsed into individual parts (`object`) | ||
* `connection` HTTP connection information when available (`object`) | ||
#### Methods | ||
* `abort(): boolean` Emit an abort event | ||
* `error(message, code, status?, original?): HttpError` Create a HTTP error instance | ||
* `abort(): boolean` Aborts the HTTP connection | ||
#### Events | ||
* `abort` Emitted when the request is aborted and MUST be handled by transport | ||
* `error` Emitted when an out-of-band error occurs (e.g. abort) and MUST be handled by the transport | ||
* `response` Emitted when the response object is being handled | ||
* `abort` Request aborted and transport _MUST_ handle | ||
* `error` An out-of-band error occurred and transport _MUST_ handle | ||
* `response` The corresponding `Response` has started | ||
* `connection` Emitted when connection information becomes available | ||
### `Response` | ||
> HTTP class for encapsulating a `Response`, extends `Common`. | ||
> HTTP class for encapsulating a `Response`, extends `Servie`. | ||
@@ -141,27 +137,29 @@ ```ts | ||
> Extends `Common` options. | ||
> Extends `Servie` options. | ||
* `status?` The HTTP response status code (`number`) | ||
* `statusText?` The HTTP response status message (`string`) | ||
* `statusCode?` The HTTP response status code (`number`) | ||
* `statusMessage?` The HTTP response status message (`string`) | ||
#### Properties | ||
* `status?` The HTTP response status code (`number`) | ||
* `statusText?` The HTTP response status message (`string`) | ||
* `statusCode` The HTTP response status code (`number`) | ||
* `statusMessage?` The HTTP response status message (`string`) | ||
* `ok` Returns whether response was successful (status in range 200-299) (`boolean`) | ||
### `Headers` | ||
> Used by `Common` for `Request` and `Response` objects. | ||
> Used by `Servie` for `Request`, `Response` and `Body` objects. | ||
#### Options | ||
Take a single parameter with the headers in object, array or `Headers` format. | ||
Take a single parameter with the headers in raw array format. | ||
**Tip:** Use `createHeaders(value?: any)` to create a `Headers` instance from raw data (e.g. `HeadersObject | string[] | null`). | ||
#### Properties | ||
* `raw` The raw HTTP headers list (`string[]`) | ||
* `rawHeaders` The raw HTTP headers list (`string[]`) | ||
#### Methods | ||
* `object(obj?: HeadersObject | null): HeadersObject | void` A getter/setter method for reading the headers as a lower-cased object (like node.js) | ||
* `set(name: string, value: string | string[]): this` Set a HTTP header by overriding case-insensitive headers of the same name | ||
@@ -173,15 +171,50 @@ * `append(name: string, value: string | string[]): this` Append a HTTP header | ||
* `delete(name: string): this` Delete a case-insensitive header | ||
* `asObject(toLower?: boolean): HeadersObject` Return the headers as a plain object | ||
* `extend(obj: HeadersObject): this` Extends the current headers with an object | ||
* `keys()` Iterable of the available header names | ||
* `values()` Iterable of header values | ||
* `entries()` Iterable of headers as `[key, value]` | ||
* `clone()` Clones the current headers instance | ||
### `HttpError` | ||
#### Static Methods | ||
> Internally and externally triggered HTTP errors. | ||
* `is(obj: any): boolean` Checks if an object is `Headers` | ||
### `Body` | ||
> Immutable representation of body used by `Request` and `Response`. | ||
#### Options | ||
```ts | ||
const body = new Body({}) | ||
``` | ||
* `rawBody` Supported body type (`any`) | ||
* `headers?` Headers related to the body, e.g. `Content-Type` (`Headers`) | ||
**Tip:** Use `createBody(value?: any)` to create a `Body` instance from raw data (e.g. `Readable | ReadableStream | Buffer | ArrayBuffer | object | string | null`). | ||
> `Body` is the most complex part of Servie due to support for node.js and browsers. TypeScript is also [missing a good story](https://github.com/Microsoft/TypeScript/issues/7753) for universal modules with code paths offering different features (e.g. `Buffer` in node.js, `ReadableStream` in browsers), so there's some logic duplication to support require via `servie/dist/body/node` and `servie/dist/body/browser`. If you are a module author only supporting browsers or node.js, feel free to use the `NodeBody` or `BrowserBody` exports to provide a better DX. | ||
#### Properties | ||
* `code` A unique error code (`string`) | ||
* `status` A HTTP status code (`number`) | ||
* `request` The `Request` instance that triggered the error (`Request`) | ||
* `message` Standard error message (`string`) | ||
* `cause` Specified when the HTTP error was triggered by an underlying error | ||
* `buffered` Indicates the raw body is entirely in memory (`boolean`) | ||
* `bodyUsed` Indicates the body has already been read (`boolean`) | ||
* `hasBody` Indicates the body has been set (not `undefined`) (`boolean`) | ||
* `headers` Set of body-related HTTP headers (`Headers`) | ||
#### Methods | ||
* `text(): Promise<string>` Returns body as a UTF-8 string | ||
* `json(): Promise<any>` Returns body parsed as JSON | ||
* `arrayBuffer(): Promise<ArrayBuffer>` Returns the body as an `ArrayBuffer` instance | ||
* `buffer(): Promise<Buffer>` Returns the body as a `Buffer` instance (node.js) | ||
* `stream(): Readable` Returns a readable node.js stream (node.js) | ||
* `readableStream(): ReadableStream` Returns a readable WHATWG stream (browsers) | ||
#### Static Methods | ||
* `is(obj: any): boolean` Checks if an object is `Body` | ||
## Implementers | ||
@@ -192,3 +225,3 @@ | ||
1. Listen to the `error` event on `Request` for out-of-band errors and respond accordingly (e.g. app-level logging) | ||
2. Listen to the `abort` event on `Request` to destroy the HTTP request | ||
2. Listen to the `abort` event on `Request` to destroy the HTTP request/response | ||
3. Emit the `response` event on `Request` when handling the response | ||
@@ -200,10 +233,6 @@ 4. Set `started === true` and `finished === true` on `Request` and `Response`, as appropriate | ||
This module is designed for ES5 environments, but also requires `Promise` to be available. | ||
This module is designed for ES2015 environments and published with [TypeScript](https://github.com/Microsoft/TypeScript) definitions on NPM. | ||
## TypeScript | ||
This project is written using [TypeScript](https://github.com/Microsoft/TypeScript) and publishes the definitions directly to NPM. | ||
## License | ||
Apache 2.0 |
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
114910
73
1192
0
226
8
1
+ Addedbyte-length@^1.0.2
+ Addedbyte-length@1.0.2(transitive)
- Removedmake-error-cause@^1.2.2
- Removedmake-error@1.3.6(transitive)
- Removedmake-error-cause@1.2.2(transitive)