superagent
Advanced tools
Comparing version 1.8.3 to 2.0.0-alpha.1
{ | ||
"name": "superagent", | ||
"repo": "visionmedia/superagent", | ||
"version": "1.8.3", | ||
"version": "1.9.0", | ||
"description": "elegant & feature rich browser / node HTTP with a fluent API", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
@@ -37,2 +37,6 @@ | ||
ES6 promises are supported. Instead of `.end()` you can call `.then()`: | ||
request('GET', '/search').then(success, failure); | ||
The __node__ client may also provide absolute urls: | ||
@@ -197,2 +201,6 @@ | ||
## Serializing request body | ||
Superagent will automatically serialize JSON and forms. If you want to send the payload in a custom format, you can replace the built-in serialization with `.serialize()` method. | ||
## Setting Accept | ||
@@ -224,3 +232,3 @@ | ||
Super Agent will parse known response-body data for you, currently supporting _application/x-www-form-urlencoded_, _application/json_, and _multipart/form-data_. | ||
Super Agent will parse known response-body data for you, currently supporting `application/x-www-form-urlencoded`, `application/json`, and `multipart/form-data`. You can set a custom parser (that takes precedence over built-in parsers) with the `.parse(fn)` method. | ||
@@ -257,3 +265,3 @@ ### JSON / Urlencoded | ||
property is always present for the client API, and only when the mime type | ||
matches "text/*", "*/json", or "x-www-form-urlencoding" by default for node. The | ||
matches "text/*", "*/json", or "x-www-form-urlencoded" by default for node. The | ||
reasoning is to conserve memory, as buffering text of large bodies such as multipart files or images is extremely inefficient. | ||
@@ -444,10 +452,12 @@ | ||
## Generator support | ||
## Promise and Generator support | ||
Superagent now supports easier control flow using generators. By using a generator control flow | ||
like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa), | ||
you can `yield` on any superagent method: | ||
Superagent's request is a "thenable" object that's compatible with JavaScript promises. | ||
Libraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any superagent method: | ||
var res = yield request | ||
.get('http://local') | ||
.auth('tobi', 'learnboost') | ||
Note that superagent expects the global `Promise` object to be present. You'll need a polyfill to use promises in Internet Explorer or Node.js 0.10. |
@@ -0,1 +1,27 @@ | ||
# 2.0.0 | ||
To try alpha versions: | ||
npm install superagent@next | ||
## Breaking changes | ||
Breaking changes are in rarely used functionality, so we hope upgrade will be smooth for most users. | ||
* Browser: The `.parse()` method has been renamed to `.serialize()` for consistency with NodeJS version. | ||
* Browser: Query string keys without a value used to be parsed as `'undefined'`, now their value is `''` (empty string) (shura, Kornel Lesiński). | ||
* NodeJS: The `redirect` event is called after new query string and headers have been set and is allowed to override the request URL (Kornel Lesiński) | ||
* `.then()` returns a real `Promise`. Note that use of superagent with promises now requires a global `Promise` object. | ||
If you target Internet Explorer or Node 0.10, you'll need `require('es6-promise').polyfill()` or similar. | ||
* Upgraded all dependencies (Peter Lyons) | ||
* Renamed properties documented as `@api private` to have `_prefixed` names (Kornel Lesiński) | ||
## Probably not breaking changes: | ||
* Extracted common functions to request-base (Peter Lyons) | ||
* Fixed race condition in pipe tests (Peter Lyons) | ||
* Handle `FormData` error events (scriptype) | ||
* Fixed wrong jsdoc of Request#attach (George Chung) | ||
* Updated and improved tests (Peter Lyons) | ||
# 1.8.2 (2016-03-20) | ||
@@ -2,0 +28,0 @@ |
@@ -30,26 +30,2 @@ /** | ||
/** | ||
* Check if `obj` is a host object, | ||
* we don't want to serialize these :) | ||
* | ||
* TODO: future proof, move to compoent land | ||
* | ||
* @param {Object} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function isHost(obj) { | ||
var str = {}.toString.call(obj); | ||
switch (str) { | ||
case '[object File]': | ||
case '[object Blob]': | ||
case '[object FormData]': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
/** | ||
* Expose `request`. | ||
@@ -104,4 +80,4 @@ */ | ||
pushEncodedKeyValuePair(pairs, key, obj[key]); | ||
} | ||
} | ||
} | ||
} | ||
return pairs.join('&'); | ||
@@ -146,9 +122,14 @@ } | ||
var pairs = str.split('&'); | ||
var parts; | ||
var pair; | ||
var pos; | ||
for (var i = 0, len = pairs.length; i < len; ++i) { | ||
pair = pairs[i]; | ||
parts = pair.split('='); | ||
obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); | ||
pos = pair.indexOf('='); | ||
if (pos == -1) { | ||
obj[decodeURIComponent(pair)] = ''; | ||
} else { | ||
obj[decodeURIComponent(pair.slice(0, pos))] = | ||
decodeURIComponent(pair.slice(pos + 1)); | ||
} | ||
} | ||
@@ -337,3 +318,3 @@ | ||
this.statusText = this.req.xhr.statusText; | ||
this.setStatusProperties(this.xhr.status); | ||
this._setStatusProperties(this.xhr.status); | ||
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); | ||
@@ -344,5 +325,5 @@ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but | ||
this.header['content-type'] = this.xhr.getResponseHeader('content-type'); | ||
this.setHeaderProperties(this.header); | ||
this._setHeaderProperties(this.header); | ||
this.body = this.req.method != 'HEAD' | ||
? this.parseBody(this.text ? this.text : this.xhr.response) | ||
? this._parseBody(this.text ? this.text : this.xhr.response) | ||
: null; | ||
@@ -375,3 +356,3 @@ } | ||
Response.prototype.setHeaderProperties = function(header){ | ||
Response.prototype._setHeaderProperties = function(header){ | ||
// content-type | ||
@@ -397,3 +378,3 @@ var ct = this.header['content-type'] || ''; | ||
Response.prototype.parseBody = function(str){ | ||
Response.prototype._parseBody = function(str){ | ||
var parse = request.parse[this.type]; | ||
@@ -429,3 +410,3 @@ if (!parse && isJSON(this.type)) { | ||
Response.prototype.setStatusProperties = function(status){ | ||
Response.prototype._setStatusProperties = function(status){ | ||
// handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request | ||
@@ -549,18 +530,2 @@ if (status === 1223) { | ||
/** | ||
* Abort the request, and clear potential timeout. | ||
* | ||
* @return {Request} | ||
* @api public | ||
*/ | ||
Request.prototype.abort = function(){ | ||
if (this.aborted) return; | ||
this.aborted = true; | ||
this.xhr.abort(); | ||
this.clearTimeout(); | ||
this.emit('abort'); | ||
return this; | ||
}; | ||
/** | ||
* Set Content-Type to `type`, mapping values from `request.types`. | ||
@@ -593,3 +558,3 @@ * | ||
/** | ||
* Set responseType to `val`. Presently valid responseTypes are 'blob' and | ||
* Set responseType to `val`. Presently valid responseTypes are 'blob' and | ||
* 'arraybuffer'. | ||
@@ -695,3 +660,3 @@ * | ||
* request.post('/upload') | ||
* .attach(new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"})) | ||
* .attach('content', new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"})) | ||
* .end(callback); | ||
@@ -720,86 +685,2 @@ * ``` | ||
/** | ||
* Send `data` as the request body, defaulting the `.type()` to "json" when | ||
* an object is given. | ||
* | ||
* Examples: | ||
* | ||
* // manual json | ||
* request.post('/user') | ||
* .type('json') | ||
* .send('{"name":"tj"}') | ||
* .end(callback) | ||
* | ||
* // auto json | ||
* request.post('/user') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // manual x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send('name=tj') | ||
* .end(callback) | ||
* | ||
* // auto x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // defaults to x-www-form-urlencoded | ||
* request.post('/user') | ||
* .send('name=tobi') | ||
* .send('species=ferret') | ||
* .end(callback) | ||
* | ||
* @param {String|Object} data | ||
* @return {Request} for chaining | ||
* @api public | ||
*/ | ||
Request.prototype.send = function(data){ | ||
var obj = isObject(data); | ||
var type = this._header['content-type']; | ||
// merge | ||
if (obj && isObject(this._data)) { | ||
for (var key in data) { | ||
this._data[key] = data[key]; | ||
} | ||
} else if ('string' == typeof data) { | ||
if (!type) this.type('form'); | ||
type = this._header['content-type']; | ||
if ('application/x-www-form-urlencoded' == type) { | ||
this._data = this._data | ||
? this._data + '&' + data | ||
: data; | ||
} else { | ||
this._data = (this._data || '') + data; | ||
} | ||
} else { | ||
this._data = data; | ||
} | ||
if (!obj || isHost(data)) return this; | ||
if (!type) this.type('json'); | ||
return this; | ||
}; | ||
/** | ||
* @deprecated | ||
*/ | ||
Response.prototype.parse = function serialize(fn){ | ||
if (root.console) { | ||
console.warn("Client-side parse() method has been renamed to serialize(). This method is not compatible with superagent v2.0"); | ||
} | ||
this.serialize(fn); | ||
return this; | ||
}; | ||
Response.prototype.serialize = function serialize(fn){ | ||
this._parser = fn; | ||
return this; | ||
}; | ||
/** | ||
* Invoke the callback with `err` and `res` | ||
@@ -842,3 +723,3 @@ * and handle arity check. | ||
Request.prototype.timeoutError = function(){ | ||
Request.prototype._timeoutError = function(){ | ||
var timeout = this._timeout; | ||
@@ -850,18 +731,3 @@ var err = new Error('timeout of ' + timeout + 'ms exceeded'); | ||
/** | ||
* Enable transmission of cookies with x-domain requests. | ||
* | ||
* Note that for this to work the origin must not be | ||
* using "Access-Control-Allow-Origin" with a wildcard, | ||
* and also must set "Access-Control-Allow-Credentials" | ||
* to "true". | ||
* | ||
* @api public | ||
*/ | ||
Request.prototype.withCredentials = function(){ | ||
this._withCredentials = true; | ||
return this; | ||
}; | ||
/** | ||
@@ -896,4 +762,4 @@ * Initiate request, invoking callback `fn(res)` | ||
if (0 == status) { | ||
if (self.timedout) return self.timeoutError(); | ||
if (self.aborted) return; | ||
if (self.timedout) return self._timeoutError(); | ||
if (self._aborted) return; | ||
return self.crossDomainError(); | ||
@@ -952,6 +818,6 @@ } | ||
// body | ||
if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) { | ||
if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !this._isHost(data)) { | ||
// serialize stuff | ||
var contentType = this._header['content-type']; | ||
var serialize = this._parser || request.serialize[contentType ? contentType.split(';')[0] : '']; | ||
var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; | ||
if (!serialize && isJSON(contentType)) serialize = request.serialize['application/json']; | ||
@@ -1024,2 +890,20 @@ if (serialize) data = serialize(data); | ||
/** | ||
* OPTIONS query to `url` with optional callback `fn(res)`. | ||
* | ||
* @param {String} url | ||
* @param {Mixed|Function} data or fn | ||
* @param {Function} fn | ||
* @return {Request} | ||
* @api public | ||
*/ | ||
request.options = function(url, data, fn){ | ||
var req = request('OPTIONS', url); | ||
if ('function' == typeof data) fn = data, data = null; | ||
if (data) req.send(data); | ||
if (fn) req.end(fn); | ||
return req; | ||
}; | ||
/** | ||
* DELETE `url` with optional callback `fn(res)`. | ||
@@ -1026,0 +910,0 @@ * |
@@ -38,3 +38,3 @@ | ||
Agent.prototype.saveCookies = function(res){ | ||
Agent.prototype._saveCookies = function(res){ | ||
var cookies = res.headers['set-cookie']; | ||
@@ -51,3 +51,3 @@ if (cookies) this.jar.setCookies(cookies); | ||
Agent.prototype.attachCookies = function(req){ | ||
Agent.prototype._attachCookies = function(req){ | ||
var url = parse(req.url); | ||
@@ -76,6 +76,6 @@ var access = CookieAccess(url.hostname, url.pathname, 'https:' == url.protocol); | ||
req.on('response', this.saveCookies.bind(this)); | ||
req.on('redirect', this.saveCookies.bind(this)); | ||
req.on('redirect', this.attachCookies.bind(this, req)); | ||
this.attachCookies(req); | ||
req.on('response', this._saveCookies.bind(this)); | ||
req.on('redirect', this._saveCookies.bind(this)); | ||
req.on('redirect', this._attachCookies.bind(this, req)); | ||
this._attachCookies(req); | ||
@@ -82,0 +82,0 @@ fn && req.end(fn); |
@@ -326,76 +326,2 @@ | ||
/** | ||
* Send `data` as the request body, defaulting the `.type()` to "json" when | ||
* an object is given. | ||
* | ||
* Examples: | ||
* | ||
* // manual json | ||
* request.post('/user') | ||
* .type('json') | ||
* .send('{"name":"tj"}') | ||
* .end(callback) | ||
* | ||
* // auto json | ||
* request.post('/user') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // manual x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send('name=tj') | ||
* .end(callback) | ||
* | ||
* // auto x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // string defaults to x-www-form-urlencoded | ||
* request.post('/user') | ||
* .send('name=tj') | ||
* .send('foo=bar') | ||
* .send('bar=baz') | ||
* .end(callback) | ||
* | ||
* @param {String|Object} data | ||
* @return {Request} for chaining | ||
* @api public | ||
*/ | ||
Request.prototype.send = function(data){ | ||
var obj = isObject(data); | ||
var type = this._header['content-type']; | ||
// merge | ||
if (obj && isObject(this._data)) { | ||
for (var key in data) { | ||
this._data[key] = data[key]; | ||
} | ||
// string | ||
} else if ('string' == typeof data) { | ||
// default to x-www-form-urlencoded | ||
if (!type) this.type('form'); | ||
type = this._header['content-type']; | ||
// concat & | ||
if ('application/x-www-form-urlencoded' == type) { | ||
this._data = this._data | ||
? this._data + '&' + data | ||
: data; | ||
} else { | ||
this._data = (this._data || '') + data; | ||
} | ||
} else { | ||
this._data = data; | ||
} | ||
if (!obj) return this; | ||
// default to json | ||
if (!type) this.type('json'); | ||
return this; | ||
}; | ||
/** | ||
* Write raw `data` / `encoding` to the socket. | ||
@@ -415,3 +341,3 @@ * | ||
// ensure querystring is appended before headers are sent | ||
this.appendQueryString(req); | ||
this._appendQueryString(req); | ||
} catch (e) { | ||
@@ -441,3 +367,3 @@ return this.emit('error', e); | ||
if (redirect && self._redirects++ != self._maxRedirects) { | ||
return self.redirect(res).pipe(stream, options); | ||
return self._redirect(res).pipe(stream, options); | ||
} | ||
@@ -473,16 +399,2 @@ | ||
/** | ||
* Abort and clear timeout. | ||
* | ||
* @api public | ||
*/ | ||
Request.prototype.abort = function(){ | ||
debug('abort %s %s', this.method, this.url); | ||
this._aborted = true; | ||
this.clearTimeout(); | ||
this.req.abort(); | ||
this.emit('abort'); | ||
}; | ||
/** | ||
* Redirect to `url | ||
@@ -495,3 +407,3 @@ * | ||
Request.prototype.redirect = function(res){ | ||
Request.prototype._redirect = function(res){ | ||
var url = res.headers.location; | ||
@@ -553,7 +465,7 @@ if (!url) { | ||
this.url = url; | ||
this._redirectList.push(url); | ||
this.emit('redirect', res); | ||
this.qs = {}; | ||
this.qsRaw = []; | ||
this.set(headers); | ||
this.emit('redirect', res); | ||
this._redirectList.push(this.url); | ||
this.end(this._callback); | ||
@@ -719,3 +631,3 @@ return this; | ||
Request.prototype.appendQueryString = function(req){ | ||
Request.prototype._appendQueryString = function(req){ | ||
var querystring = qs.stringify(this.qs, { indices: false }); | ||
@@ -737,12 +649,2 @@ querystring += ((querystring.length && this.qsRaw.length) ? '&' : '') + this.qsRaw.join('&'); | ||
/** | ||
* Client API parity, irrelevant in a Node context. | ||
* | ||
* @api public | ||
*/ | ||
Request.prototype.withCredentials = function(){ | ||
return this; | ||
}; | ||
Request.prototype.end = function(fn){ | ||
@@ -762,3 +664,3 @@ var self = this; | ||
try { | ||
this.appendQueryString(req); | ||
this._appendQueryString(req); | ||
} catch (e) { | ||
@@ -829,3 +731,3 @@ return this.callback(e); | ||
if (redirect && self._redirects++ != max) { | ||
return self.redirect(res); | ||
return self._redirect(res); | ||
} | ||
@@ -1006,17 +908,2 @@ | ||
/** | ||
* To json. | ||
* | ||
* @return {Object} | ||
* @api public | ||
*/ | ||
Request.prototype.toJSON = function(){ | ||
return { | ||
method: this.method, | ||
url: this.url, | ||
data: this._data | ||
}; | ||
}; | ||
/** | ||
* Expose `Request`. | ||
@@ -1023,0 +910,0 @@ */ |
@@ -42,4 +42,4 @@ | ||
this.header = this.headers = res.headers; | ||
this.setStatusProperties(res.statusCode); | ||
this.setHeaderProperties(this.header); | ||
this._setStatusProperties(res.statusCode); | ||
this._setHeaderProperties(this.header); | ||
this.setEncoding = res.setEncoding.bind(res); | ||
@@ -128,3 +128,3 @@ res.on('data', this.emit.bind(this, 'data')); | ||
Response.prototype.setHeaderProperties = function(header){ | ||
Response.prototype._setHeaderProperties = function(header){ | ||
// TODO: moar! | ||
@@ -171,3 +171,3 @@ // TODO: make this a util | ||
Response.prototype.setStatusProperties = function(status){ | ||
Response.prototype._setStatusProperties = function(status){ | ||
var type = status / 100 | 0; | ||
@@ -174,0 +174,0 @@ |
@@ -20,5 +20,5 @@ /** | ||
/** | ||
* Force given parser | ||
* Override default response body parser | ||
* | ||
* Sets the body parser no matter type. | ||
* This function will be called to convert incoming data into request.body | ||
* | ||
@@ -35,2 +35,16 @@ * @param {Function} | ||
/** | ||
* Override default request body serializer | ||
* | ||
* This function will be called to convert data set via .send or .attach into payload to send | ||
* | ||
* @param {Function} | ||
* @api public | ||
*/ | ||
exports.serialize = function serialize(fn){ | ||
this._serializer = fn; | ||
return this; | ||
}; | ||
/** | ||
* Set timeout to `ms`. | ||
@@ -49,5 +63,5 @@ * | ||
/** | ||
* Faux promise support | ||
* Promise support | ||
* | ||
* @param {Function} fulfill | ||
* @param {Function} resolve | ||
* @param {Function} reject | ||
@@ -57,6 +71,12 @@ * @return {Request} | ||
exports.then = function then(fulfill, reject) { | ||
return this.end(function(err, res) { | ||
err ? reject(err) : fulfill(res); | ||
}); | ||
exports.then = function then(resolve, reject) { | ||
if (!this._fullfilledPromise) { | ||
var self = this; | ||
this._fullfilledPromise = new Promise(function(innerResolve, innerReject){ | ||
self.end(function(err, res){ | ||
if (err) innerReject(err); else innerResolve(res); | ||
}); | ||
}); | ||
} | ||
return this._fullfilledPromise.then(resolve, reject); | ||
} | ||
@@ -171,1 +191,149 @@ | ||
}; | ||
/** | ||
* Abort the request, and clear potential timeout. | ||
* | ||
* @return {Request} | ||
* @api public | ||
*/ | ||
exports.abort = function(){ | ||
if (this._aborted) { | ||
return this; | ||
} | ||
this._aborted = true; | ||
this.xhr && this.xhr.abort(); // browser | ||
this.req && this.req.abort(); // node | ||
this.clearTimeout(); | ||
this.emit('abort'); | ||
return this; | ||
}; | ||
/** | ||
* Enable transmission of cookies with x-domain requests. | ||
* | ||
* Note that for this to work the origin must not be | ||
* using "Access-Control-Allow-Origin" with a wildcard, | ||
* and also must set "Access-Control-Allow-Credentials" | ||
* to "true". | ||
* | ||
* @api public | ||
*/ | ||
exports.withCredentials = function(){ | ||
// This is browser-only functionality. Node side is no-op. | ||
this._withCredentials = true; | ||
return this; | ||
}; | ||
/** | ||
* Convert to a plain javascript object (not JSON string) of scalar properties. | ||
* Note as this method is designed to return a useful non-this value, | ||
* it cannot be chained. | ||
* | ||
* @return {Object} describing method, url, and data of this request | ||
* @api public | ||
*/ | ||
exports.toJSON = function(){ | ||
return { | ||
method: this.method, | ||
url: this.url, | ||
data: this._data | ||
}; | ||
}; | ||
/** | ||
* Check if `obj` is a host object, | ||
* we don't want to serialize these :) | ||
* | ||
* TODO: future proof, move to compoent land | ||
* | ||
* @param {Object} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
exports._isHost = function _isHost(obj) { | ||
var str = {}.toString.call(obj); | ||
switch (str) { | ||
case '[object File]': | ||
case '[object Blob]': | ||
case '[object FormData]': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
/** | ||
* Send `data` as the request body, defaulting the `.type()` to "json" when | ||
* an object is given. | ||
* | ||
* Examples: | ||
* | ||
* // manual json | ||
* request.post('/user') | ||
* .type('json') | ||
* .send('{"name":"tj"}') | ||
* .end(callback) | ||
* | ||
* // auto json | ||
* request.post('/user') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // manual x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send('name=tj') | ||
* .end(callback) | ||
* | ||
* // auto x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // defaults to x-www-form-urlencoded | ||
* request.post('/user') | ||
* .send('name=tobi') | ||
* .send('species=ferret') | ||
* .end(callback) | ||
* | ||
* @param {String|Object} data | ||
* @return {Request} for chaining | ||
* @api public | ||
*/ | ||
exports.send = function(data){ | ||
var obj = isObject(data); | ||
var type = this._header['content-type']; | ||
// merge | ||
if (obj && isObject(this._data)) { | ||
for (var key in data) { | ||
this._data[key] = data[key]; | ||
} | ||
} else if ('string' == typeof data) { | ||
// default to x-www-form-urlencoded | ||
if (!type) this.type('form'); | ||
type = this._header['content-type']; | ||
if ('application/x-www-form-urlencoded' == type) { | ||
this._data = this._data | ||
? this._data + '&' + data | ||
: data; | ||
} else { | ||
this._data = (this._data || '') + data; | ||
} | ||
} else { | ||
this._data = data; | ||
} | ||
if (!obj || this._isHost(data)) return this; | ||
// default to json | ||
if (!type) this.type('json'); | ||
return this; | ||
}; |
{ | ||
"name": "superagent", | ||
"version": "1.8.3", | ||
"version": "2.0.0-alpha.1", | ||
"description": "elegant & feature rich browser / node HTTP with a fluent API", | ||
@@ -27,27 +27,28 @@ "scripts": { | ||
"dependencies": { | ||
"qs": "2.3.3", | ||
"formidable": "~1.0.14", | ||
"mime": "1.3.4", | ||
"component-emitter": "~1.2.0", | ||
"methods": "~1.1.1", | ||
"cookiejar": "2.0.6", | ||
"debug": "2", | ||
"reduce-component": "1.0.1", | ||
"extend": "3.0.0", | ||
"form-data": "1.0.0-rc3", | ||
"readable-stream": "1.0.27-1" | ||
"qs": "^6.1.0", | ||
"formidable": "^1.0.17", | ||
"mime": "^1.3.4", | ||
"component-emitter": "^1.2.0", | ||
"methods": "^1.1.1", | ||
"cookiejar": "^2.0.6", | ||
"debug": "^2.2.0", | ||
"reduce-component": "^1.0.1", | ||
"extend": "^3.0.0", | ||
"form-data": "1.0.0-rc4", | ||
"readable-stream": "^2.0.5" | ||
}, | ||
"devDependencies": { | ||
"Base64": "~0.3.0", | ||
"basic-auth-connect": "~1.0.0", | ||
"better-assert": "~1.0.1", | ||
"body-parser": "~1.9.2", | ||
"browserify": "~6.3.2", | ||
"cookie-parser": "~1.3.3", | ||
"express": "~4.9.8", | ||
"express-session": "~1.9.1", | ||
"marked": "0.3.5", | ||
"mocha": "~2.0.1", | ||
"should": "~3.1.3", | ||
"zuul": "~1.19.0" | ||
"Base64": "^0.3.0", | ||
"basic-auth-connect": "^1.0.0", | ||
"better-assert": "^1.0.1", | ||
"body-parser": "^1.15.0", | ||
"browserify": "^13.0.0", | ||
"cookie-parser": "^1.4.1", | ||
"express": "^4.13.4", | ||
"express-session": "^1.13.0", | ||
"marked": "^0.3.5", | ||
"mocha": "^2.4.5", | ||
"should": "^8.2.2", | ||
"should-http": "^0.0.4", | ||
"zuul": "^3.10.1" | ||
}, | ||
@@ -67,4 +68,4 @@ "browser": { | ||
"engines": { | ||
"node": ">= 0.8" | ||
"node": ">= 0.10" | ||
} | ||
} |
@@ -78,2 +78,3 @@ # SuperAgent [![Build Status](https://travis-ci.org/visionmedia/superagent.svg?branch=master)](https://travis-ci.org/visionmedia/superagent) | ||
* [superagent-use](https://github.com/koenpunt/superagent-use) - A client addon to apply plugins to all requests. | ||
* [superagent-httpbackend](https://www.npmjs.com/package/superagent-httpbackend) - stub out requests using AngularJS' $httpBackend syntax | ||
@@ -115,4 +116,17 @@ Please prefix your plugin with `superagent-*` so that it can easily be found by others. | ||
## Packaging Notes for Developers | ||
**npm (for node)** is configured via the `package.json` file and the `.npmignore` file. Key metadata in the `package.json` file is the `version` field which should be changed according to semantic versioning and have a 1-1 correspondence with git tags. So for example, if you were to `git show v1.5.0:package.json | grep version`, you should see `"version": "1.5.0",` and this should hold true for every release. This can be handled via the `npm version` command. Be aware that when publishing, npm will presume the version being published should also be tagged in npm as `latest`, which is OK for normal incremental releases. For betas and minor/patch releases to older versions, be sure to include `--tag` appropriately to avoid an older release getting tagged as `latest`. | ||
**npm (for browser standalone)** When we publish versions to npm, we run `make superagent.js` which generates the standalone `superagent.js` file via `browserify`, and this file is included in the package published to npm (but this file is never checked into the git repository). If users want to install via npm but serve a single `.js` file directly to the browser, the `node_modules/superagent/superagent.js` is a standalone browserified file ready to go for that purpose. It is not minified. | ||
**npm (for browserify)** is handled via the `package.json` `browser` field which allows users to install superagent via npm, reference it from their browser code with `require('superagent')`, and then build their own application bundle via `browserify`, which will use `lib/client.js` as the superagent entrypoint. | ||
**bower** is configured via the `bower.json` file. Bower installs files directly from git/github without any transformation. | ||
**component** is configured via the `component.json` file. | ||
## License | ||
MIT |
@@ -1,2 +0,2 @@ | ||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.superagent = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.superagent=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
/** | ||
@@ -36,5 +36,5 @@ * Check if `obj` is an object. | ||
/** | ||
* Force given parser | ||
* Override default response body parser | ||
* | ||
* Sets the body parser no matter type. | ||
* This function will be called to convert incoming data into request.body | ||
* | ||
@@ -51,2 +51,16 @@ * @param {Function} | ||
/** | ||
* Override default request body serializer | ||
* | ||
* This function will be called to convert data set via .send or .attach into payload to send | ||
* | ||
* @param {Function} | ||
* @api public | ||
*/ | ||
exports.serialize = function serialize(fn){ | ||
this._serializer = fn; | ||
return this; | ||
}; | ||
/** | ||
* Set timeout to `ms`. | ||
@@ -65,5 +79,5 @@ * | ||
/** | ||
* Faux promise support | ||
* Promise support | ||
* | ||
* @param {Function} fulfill | ||
* @param {Function} resolve | ||
* @param {Function} reject | ||
@@ -73,6 +87,12 @@ * @return {Request} | ||
exports.then = function then(fulfill, reject) { | ||
return this.end(function(err, res) { | ||
err ? reject(err) : fulfill(res); | ||
}); | ||
exports.then = function then(resolve, reject) { | ||
if (!this._fullfilledPromise) { | ||
var self = this; | ||
this._fullfilledPromise = new Promise(function(innerResolve, innerReject){ | ||
self.end(function(err, res){ | ||
if (err) innerReject(err); else innerResolve(res); | ||
}); | ||
}); | ||
} | ||
return this._fullfilledPromise.then(resolve, reject); | ||
} | ||
@@ -188,2 +208,150 @@ | ||
/** | ||
* Abort the request, and clear potential timeout. | ||
* | ||
* @return {Request} | ||
* @api public | ||
*/ | ||
exports.abort = function(){ | ||
if (this._aborted) { | ||
return this; | ||
} | ||
this._aborted = true; | ||
this.xhr && this.xhr.abort(); // browser | ||
this.req && this.req.abort(); // node | ||
this.clearTimeout(); | ||
this.emit('abort'); | ||
return this; | ||
}; | ||
/** | ||
* Enable transmission of cookies with x-domain requests. | ||
* | ||
* Note that for this to work the origin must not be | ||
* using "Access-Control-Allow-Origin" with a wildcard, | ||
* and also must set "Access-Control-Allow-Credentials" | ||
* to "true". | ||
* | ||
* @api public | ||
*/ | ||
exports.withCredentials = function(){ | ||
// This is browser-only functionality. Node side is no-op. | ||
this._withCredentials = true; | ||
return this; | ||
}; | ||
/** | ||
* Convert to a plain javascript object (not JSON string) of scalar properties. | ||
* Note as this method is designed to return a useful non-this value, | ||
* it cannot be chained. | ||
* | ||
* @return {Object} describing method, url, and data of this request | ||
* @api public | ||
*/ | ||
exports.toJSON = function(){ | ||
return { | ||
method: this.method, | ||
url: this.url, | ||
data: this._data | ||
}; | ||
}; | ||
/** | ||
* Check if `obj` is a host object, | ||
* we don't want to serialize these :) | ||
* | ||
* TODO: future proof, move to compoent land | ||
* | ||
* @param {Object} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
exports._isHost = function _isHost(obj) { | ||
var str = {}.toString.call(obj); | ||
switch (str) { | ||
case '[object File]': | ||
case '[object Blob]': | ||
case '[object FormData]': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
/** | ||
* Send `data` as the request body, defaulting the `.type()` to "json" when | ||
* an object is given. | ||
* | ||
* Examples: | ||
* | ||
* // manual json | ||
* request.post('/user') | ||
* .type('json') | ||
* .send('{"name":"tj"}') | ||
* .end(callback) | ||
* | ||
* // auto json | ||
* request.post('/user') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // manual x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send('name=tj') | ||
* .end(callback) | ||
* | ||
* // auto x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // defaults to x-www-form-urlencoded | ||
* request.post('/user') | ||
* .send('name=tobi') | ||
* .send('species=ferret') | ||
* .end(callback) | ||
* | ||
* @param {String|Object} data | ||
* @return {Request} for chaining | ||
* @api public | ||
*/ | ||
exports.send = function(data){ | ||
var obj = isObject(data); | ||
var type = this._header['content-type']; | ||
// merge | ||
if (obj && isObject(this._data)) { | ||
for (var key in data) { | ||
this._data[key] = data[key]; | ||
} | ||
} else if ('string' == typeof data) { | ||
// default to x-www-form-urlencoded | ||
if (!type) this.type('form'); | ||
type = this._header['content-type']; | ||
if ('application/x-www-form-urlencoded' == type) { | ||
this._data = this._data | ||
? this._data + '&' + data | ||
: data; | ||
} else { | ||
this._data = (this._data || '') + data; | ||
} | ||
} else { | ||
this._data = data; | ||
} | ||
if (!obj || this._isHost(data)) return this; | ||
// default to json | ||
if (!type) this.type('json'); | ||
return this; | ||
}; | ||
},{"./is-object":1}],3:[function(require,module,exports){ | ||
@@ -441,26 +609,2 @@ // The node and browser modules expose versions of this with the | ||
/** | ||
* Check if `obj` is a host object, | ||
* we don't want to serialize these :) | ||
* | ||
* TODO: future proof, move to compoent land | ||
* | ||
* @param {Object} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function isHost(obj) { | ||
var str = {}.toString.call(obj); | ||
switch (str) { | ||
case '[object File]': | ||
case '[object Blob]': | ||
case '[object FormData]': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
/** | ||
* Expose `request`. | ||
@@ -515,4 +659,4 @@ */ | ||
pushEncodedKeyValuePair(pairs, key, obj[key]); | ||
} | ||
} | ||
} | ||
} | ||
return pairs.join('&'); | ||
@@ -557,9 +701,14 @@ } | ||
var pairs = str.split('&'); | ||
var parts; | ||
var pair; | ||
var pos; | ||
for (var i = 0, len = pairs.length; i < len; ++i) { | ||
pair = pairs[i]; | ||
parts = pair.split('='); | ||
obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); | ||
pos = pair.indexOf('='); | ||
if (pos == -1) { | ||
obj[decodeURIComponent(pair)] = ''; | ||
} else { | ||
obj[decodeURIComponent(pair.slice(0, pos))] = | ||
decodeURIComponent(pair.slice(pos + 1)); | ||
} | ||
} | ||
@@ -748,3 +897,3 @@ | ||
this.statusText = this.req.xhr.statusText; | ||
this.setStatusProperties(this.xhr.status); | ||
this._setStatusProperties(this.xhr.status); | ||
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); | ||
@@ -755,5 +904,5 @@ // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but | ||
this.header['content-type'] = this.xhr.getResponseHeader('content-type'); | ||
this.setHeaderProperties(this.header); | ||
this._setHeaderProperties(this.header); | ||
this.body = this.req.method != 'HEAD' | ||
? this.parseBody(this.text ? this.text : this.xhr.response) | ||
? this._parseBody(this.text ? this.text : this.xhr.response) | ||
: null; | ||
@@ -786,3 +935,3 @@ } | ||
Response.prototype.setHeaderProperties = function(header){ | ||
Response.prototype._setHeaderProperties = function(header){ | ||
// content-type | ||
@@ -808,3 +957,3 @@ var ct = this.header['content-type'] || ''; | ||
Response.prototype.parseBody = function(str){ | ||
Response.prototype._parseBody = function(str){ | ||
var parse = request.parse[this.type]; | ||
@@ -840,3 +989,3 @@ if (!parse && isJSON(this.type)) { | ||
Response.prototype.setStatusProperties = function(status){ | ||
Response.prototype._setStatusProperties = function(status){ | ||
// handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request | ||
@@ -960,18 +1109,2 @@ if (status === 1223) { | ||
/** | ||
* Abort the request, and clear potential timeout. | ||
* | ||
* @return {Request} | ||
* @api public | ||
*/ | ||
Request.prototype.abort = function(){ | ||
if (this.aborted) return; | ||
this.aborted = true; | ||
this.xhr.abort(); | ||
this.clearTimeout(); | ||
this.emit('abort'); | ||
return this; | ||
}; | ||
/** | ||
* Set Content-Type to `type`, mapping values from `request.types`. | ||
@@ -1004,3 +1137,3 @@ * | ||
/** | ||
* Set responseType to `val`. Presently valid responseTypes are 'blob' and | ||
* Set responseType to `val`. Presently valid responseTypes are 'blob' and | ||
* 'arraybuffer'. | ||
@@ -1106,3 +1239,3 @@ * | ||
* request.post('/upload') | ||
* .attach(new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"})) | ||
* .attach('content', new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"})) | ||
* .end(callback); | ||
@@ -1131,86 +1264,2 @@ * ``` | ||
/** | ||
* Send `data` as the request body, defaulting the `.type()` to "json" when | ||
* an object is given. | ||
* | ||
* Examples: | ||
* | ||
* // manual json | ||
* request.post('/user') | ||
* .type('json') | ||
* .send('{"name":"tj"}') | ||
* .end(callback) | ||
* | ||
* // auto json | ||
* request.post('/user') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // manual x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send('name=tj') | ||
* .end(callback) | ||
* | ||
* // auto x-www-form-urlencoded | ||
* request.post('/user') | ||
* .type('form') | ||
* .send({ name: 'tj' }) | ||
* .end(callback) | ||
* | ||
* // defaults to x-www-form-urlencoded | ||
* request.post('/user') | ||
* .send('name=tobi') | ||
* .send('species=ferret') | ||
* .end(callback) | ||
* | ||
* @param {String|Object} data | ||
* @return {Request} for chaining | ||
* @api public | ||
*/ | ||
Request.prototype.send = function(data){ | ||
var obj = isObject(data); | ||
var type = this._header['content-type']; | ||
// merge | ||
if (obj && isObject(this._data)) { | ||
for (var key in data) { | ||
this._data[key] = data[key]; | ||
} | ||
} else if ('string' == typeof data) { | ||
if (!type) this.type('form'); | ||
type = this._header['content-type']; | ||
if ('application/x-www-form-urlencoded' == type) { | ||
this._data = this._data | ||
? this._data + '&' + data | ||
: data; | ||
} else { | ||
this._data = (this._data || '') + data; | ||
} | ||
} else { | ||
this._data = data; | ||
} | ||
if (!obj || isHost(data)) return this; | ||
if (!type) this.type('json'); | ||
return this; | ||
}; | ||
/** | ||
* @deprecated | ||
*/ | ||
Response.prototype.parse = function serialize(fn){ | ||
if (root.console) { | ||
console.warn("Client-side parse() method has been renamed to serialize(). This method is not compatible with superagent v2.0"); | ||
} | ||
this.serialize(fn); | ||
return this; | ||
}; | ||
Response.prototype.serialize = function serialize(fn){ | ||
this._parser = fn; | ||
return this; | ||
}; | ||
/** | ||
* Invoke the callback with `err` and `res` | ||
@@ -1253,3 +1302,3 @@ * and handle arity check. | ||
Request.prototype.timeoutError = function(){ | ||
Request.prototype._timeoutError = function(){ | ||
var timeout = this._timeout; | ||
@@ -1261,18 +1310,3 @@ var err = new Error('timeout of ' + timeout + 'ms exceeded'); | ||
/** | ||
* Enable transmission of cookies with x-domain requests. | ||
* | ||
* Note that for this to work the origin must not be | ||
* using "Access-Control-Allow-Origin" with a wildcard, | ||
* and also must set "Access-Control-Allow-Credentials" | ||
* to "true". | ||
* | ||
* @api public | ||
*/ | ||
Request.prototype.withCredentials = function(){ | ||
this._withCredentials = true; | ||
return this; | ||
}; | ||
/** | ||
@@ -1307,4 +1341,4 @@ * Initiate request, invoking callback `fn(res)` | ||
if (0 == status) { | ||
if (self.timedout) return self.timeoutError(); | ||
if (self.aborted) return; | ||
if (self.timedout) return self._timeoutError(); | ||
if (self._aborted) return; | ||
return self.crossDomainError(); | ||
@@ -1363,6 +1397,6 @@ } | ||
// body | ||
if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) { | ||
if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !this._isHost(data)) { | ||
// serialize stuff | ||
var contentType = this._header['content-type']; | ||
var serialize = this._parser || request.serialize[contentType ? contentType.split(';')[0] : '']; | ||
var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; | ||
if (!serialize && isJSON(contentType)) serialize = request.serialize['application/json']; | ||
@@ -1435,2 +1469,20 @@ if (serialize) data = serialize(data); | ||
/** | ||
* OPTIONS query to `url` with optional callback `fn(res)`. | ||
* | ||
* @param {String} url | ||
* @param {Mixed|Function} data or fn | ||
* @param {Function} fn | ||
* @return {Request} | ||
* @api public | ||
*/ | ||
request.options = function(url, data, fn){ | ||
var req = request('OPTIONS', url); | ||
if ('function' == typeof data) fn = data, data = null; | ||
if (data) req.send(data); | ||
if (fn) req.end(fn); | ||
return req; | ||
}; | ||
/** | ||
* DELETE `url` with optional callback `fn(res)`. | ||
@@ -1437,0 +1489,0 @@ * |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
323814
131
13
36
4249
2
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addedcomponent-emitter@1.3.1(transitive)
+ Addedcookiejar@2.1.4(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.0.0(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedform-data@1.0.0-rc4(transitive)
+ Addedformidable@1.2.6(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.6(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedmime@1.6.0(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedqs@6.13.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedside-channel@1.1.0(transitive)
+ Addedside-channel-list@1.0.0(transitive)
+ Addedside-channel-map@1.0.1(transitive)
+ Addedside-channel-weakmap@1.0.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
- Removedcomponent-emitter@1.2.1(transitive)
- Removedcookiejar@2.0.6(transitive)
- Removedextend@3.0.0(transitive)
- Removedform-data@1.0.0-rc3(transitive)
- Removedformidable@1.0.17(transitive)
- Removedisarray@0.0.1(transitive)
- Removedmime@1.3.4(transitive)
- Removedqs@2.3.3(transitive)
- Removedreadable-stream@1.0.27-1(transitive)
- Removedstring_decoder@0.10.31(transitive)
Updatedcomponent-emitter@^1.2.0
Updatedcookiejar@^2.0.6
Updateddebug@^2.2.0
Updatedextend@^3.0.0
Updatedform-data@1.0.0-rc4
Updatedformidable@^1.0.17
Updatedmethods@^1.1.1
Updatedmime@^1.3.4
Updatedqs@^6.1.0
Updatedreadable-stream@^2.0.5
Updatedreduce-component@^1.0.1