chainscript
Version:
Client for chainscript.io
2,140 lines (1,779 loc) • 58.6 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("bitcore"), require("bitcore-message"));
else if(typeof define === 'function' && define.amd)
define(["bitcore", "bitcore-message"], factory);
else if(typeof exports === 'object')
exports["chainscript"] = factory(require("bitcore"), require("bitcore-message"));
else
root["chainscript"] = factory(root["Bitcore"], root["BitcoreMessage"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_6__, __WEBPACK_EXTERNAL_MODULE_7__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _Chainscript = __webpack_require__(1);
var _Chainscript2 = _interopRequireDefault(_Chainscript);
exports['default'] = _Chainscript2['default'];
module.exports = exports['default'];
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _superagent = __webpack_require__(2);
var _superagent2 = _interopRequireDefault(_superagent);
var _objectPath = __webpack_require__(5);
var _objectPath2 = _interopRequireDefault(_objectPath);
var _bitcore = __webpack_require__(6);
var _bitcoreMessage = __webpack_require__(7);
var _bitcoreMessage2 = _interopRequireDefault(_bitcoreMessage);
var _utilsClone = __webpack_require__(8);
var _utilsClone2 = _interopRequireDefault(_utilsClone);
var _utilsDeepEquals = __webpack_require__(9);
var _utilsDeepEquals2 = _interopRequireDefault(_utilsDeepEquals);
var _utilsPromisify = __webpack_require__(13);
var _utilsPromisify2 = _interopRequireDefault(_utilsPromisify);
var Chainscript = (function () {
_createClass(Chainscript, null, [{
key: 'EXECUTE_URL',
value: 'http://agent.chainscript.io/execute',
enumerable: true
}, {
key: 'SNAPSHOTS_URL',
value: 'https://chainscript.firebaseio.com/snapshots/',
/**
* Loads a script from an existing uuid
*
* @param {string} uuid The uuid of the script
* @param {bool} [immutable=false] Whether to create an immutable instance
* @returns {Promise} A promise that resolves with a new Chainscript
*/
enumerable: true
}, {
key: 'load',
value: function value(uuid) {
var immutable = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var req = _superagent2['default'].get(Chainscript.SNAPSHOTS_URL + uuid.replace(/:/g, '-') + '.json').set('Accept', 'application/json');
return _utilsPromisify2['default'](req.end.bind(req))().then(function (res) {
if (!res.ok) {
throw new Error(res.text);
}
if (!res.body) {
throw new Error('Not found');
}
return new Chainscript(_utilsClone2['default'](res.body), immutable);
});
},
/**
* Construct a new chainscript.
*
* @param {Object | string} [script={}] The initial script
* @param {bool} [immutable=false] Whether to create an immutable instance
*/
enumerable: true
}]);
function Chainscript() {
var script = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var immutable = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
_classCallCheck(this, Chainscript);
// Clone the script for safety
this.script = _utilsClone2['default'](script);
this.immutable = immutable;
if (!immutable) {
this.initial = _utilsClone2['default'](script);
}
}
/**
* Returns the script as JSON.
*
* @returns {Object} JSON representation of the script
*/
Chainscript.prototype.toJSON = function toJSON() {
// Clone the script for safety
return _utilsClone2['default'](this.script);
};
/**
* Clones the script.
*
* @returns {Chainscript} A clone of the script
*/
Chainscript.prototype.clone = function clone() {
var copy = new Chainscript(this.script, this.immutable);
if (!this.immutable) {
copy.initial = _utilsClone2['default'](this.initial);
}
return copy;
};
/**
* Run the script.
*
* @returns {Promise} A promise that resolves with a new Chainscript
*/
Chainscript.prototype.run = function run() {
var _this = this;
if (!this.immutable) {
var initialContent = _objectPath2['default'].get(this.initial, 'body.content');
var currentContent = _objectPath2['default'].get(this.script, 'body.content');
if (!_utilsDeepEquals2['default'](initialContent, currentContent)) {
this.script.body = this.script.body || {};
this.script.body.content = initialContent;
this.delta(currentContent, true);
}
}
var req = _superagent2['default'].post(Chainscript.EXECUTE_URL).send(this.script).set('Accept', 'application/json');
return _utilsPromisify2['default'](req.end.bind(req))().then(function (res) {
if (!res.ok) {
throw new Error(res.text);
}
if (!res.body) {
throw new Error('Not found');
}
if (_this.immutable) {
return new Chainscript(res.body, true);
}
_this.script = res.body;
_this.initial = _utilsClone2['default'](_this.script);
return _this;
});
};
/**
* Returns the value at specified path.
*/
Chainscript.prototype.get = function get(path) {
var value = _objectPath2['default'].get(this.script, path);
if (typeof value === 'undefined') {
return undefined;
}
if (this.immutable) {
return _utilsClone2['default'](value);
}
return value;
};
/**
* Sets the value at specified path.
*
* @param {string} path The path of the key to set
* @param {any} value The value
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.set = function set(path, value) {
var script = undefined;
if (this.immutable) {
script = _utilsClone2['default'](this.script);
} else {
script = this.script;
}
_objectPath2['default'].set(script, path, value);
if (this.immutable) {
return new Chainscript(script, true);
}
return this;
};
/**
* Adds a snapshot command
*
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.snapshot = function snapshot() {
return this.set('x_chainscript.snapshots_enabled', true).addCommand({ snapshot: {} });
};
/**
* Adds an update command
*
* @param {Object} updates An object with updates to apply
* @param {bool} [first=false] Whether to put the command first
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.update = function update(updates) {
var first = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
return this.addCommand({ update: updates }, first);
};
/**
* Adds a notarize command
*
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.notarize = function notarize() {
return this.addCommand({ notarize: {} });
};
/**
* Adds a send email command
*
* @param {string} to Destination email address
* @param {string} [subject] Subject
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.email = function email(to, subject) {
if (subject) {
return this.addCommand({ send_email: { to: to, subject: subject } });
}
return this.addCommand({ send_email: { to: to } });
};
/**
* Adds an update command to change the content at specified path.
*
* @param {function} fn A function that changes the content
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.change = function change(fn) {
var next = _utilsClone2['default'](this.get('body.content'));
fn(next);
return this.delta(next);
};
/**
* Adds an update command to change the content to the given content.
*
* @param {Object} next The new content
* @param {bool} [first=false] Whether to put the command first
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.delta = function delta(next) {
var first = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var prev = this.get('body.content');
if (typeof prev === 'object' && prev && typeof next === 'object' && next) {
Object.keys(prev).forEach(function (s) {
if (typeof next[s] === 'undefined') {
next[s] = null;
} else if (_utilsDeepEquals2['default'](prev[s], next[s])) {
delete next[s];
}
});
}
return this.update(next, first);
};
/**
* Adds a sign content command.
*
* @param {string} wif A private key in WIF format
* @returns {Chainscript} A new instance of Chainscript
*/
Chainscript.prototype.sign = function sign(wif) {
var _sign_content;
var digest = _objectPath2['default'].get(this.script, 'body.x_meta.content_digest');
if (typeof digest === 'undefined') {
throw new Error('Content has no digest');
}
var privateKey = _bitcore.PrivateKey.fromWIF(wif);
var address = privateKey.toPublicKey().toAddress().toString();
var message = new _bitcoreMessage2['default'](digest);
var signature = message.sign(privateKey);
return this.addCommand({ sign_content: (_sign_content = {}, _sign_content[address] = { digest: digest, signature: signature }, _sign_content) });
};
Chainscript.prototype.getNumCommands = function getNumCommands() {
if (typeof this.script.execute === 'undefined') {
return 0;
}
return Object.keys(this.script.execute).length;
};
Chainscript.prototype.addCommand = function addCommand(command) {
var first = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var index = first ? 0 : this.getNumCommands();
var script = undefined;
if (this.immutable) {
script = _utilsClone2['default'](this.script);
} else {
script = this.script;
}
script.execute = script.execute || {};
if (first) {
(function () {
var tmp = {};
Object.keys(script.execute).forEach(function (s) {
tmp[parseInt(s, 10) + 1] = script.execute[s];
});
script.execute = tmp;
})();
}
script.execute[index] = command;
if (this.immutable) {
return new Chainscript(script, true);
}
return this;
};
return Chainscript;
})();
exports['default'] = Chainscript;
module.exports = exports['default'];
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
/**
* Module dependencies.
*/
var Emitter = __webpack_require__(3);
var reduce = __webpack_require__(4);
/**
* Root reference for iframes.
*/
var root;
if (typeof window !== 'undefined') { // Browser window
root = window;
} else if (typeof self !== 'undefined') { // Web Worker
root = self;
} else { // Other environments
root = this;
}
/**
* Noop.
*/
function noop(){};
/**
* 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;
}
}
/**
* Determine XHR.
*/
request.getXHR = function () {
if (root.XMLHttpRequest
&& (!root.location || 'file:' != root.location.protocol
|| !root.ActiveXObject)) {
return new XMLHttpRequest;
} else {
try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}
try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}
try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
}
return false;
};
/**
* Removes leading and trailing whitespace, added to support IE.
*
* @param {String} s
* @return {String}
* @api private
*/
var trim = ''.trim
? function(s) { return s.trim(); }
: function(s) { return s.replace(/(^\s*|\s*$)/g, ''); };
/**
* Check if `obj` is an object.
*
* @param {Object} obj
* @return {Boolean}
* @api private
*/
function isObject(obj) {
return obj === Object(obj);
}
/**
* Serialize the given `obj`.
*
* @param {Object} obj
* @return {String}
* @api private
*/
function serialize(obj) {
if (!isObject(obj)) return obj;
var pairs = [];
for (var key in obj) {
if (null != obj[key]) {
pairs.push(encodeURIComponent(key)
+ '=' + encodeURIComponent(obj[key]));
}
}
return pairs.join('&');
}
/**
* Expose serialization method.
*/
request.serializeObject = serialize;
/**
* Parse the given x-www-form-urlencoded `str`.
*
* @param {String} str
* @return {Object}
* @api private
*/
function parseString(str) {
var obj = {};
var pairs = str.split('&');
var parts;
var pair;
for (var i = 0, len = pairs.length; i < len; ++i) {
pair = pairs[i];
parts = pair.split('=');
obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
return obj;
}
/**
* Expose parser.
*/
request.parseString = parseString;
/**
* Default MIME type map.
*
* superagent.types.xml = 'application/xml';
*
*/
request.types = {
html: 'text/html',
json: 'application/json',
xml: 'application/xml',
urlencoded: 'application/x-www-form-urlencoded',
'form': 'application/x-www-form-urlencoded',
'form-data': 'application/x-www-form-urlencoded'
};
/**
* Default serialization map.
*
* superagent.serialize['application/xml'] = function(obj){
* return 'generated xml here';
* };
*
*/
request.serialize = {
'application/x-www-form-urlencoded': serialize,
'application/json': JSON.stringify
};
/**
* Default parsers.
*
* superagent.parse['application/xml'] = function(str){
* return { object parsed from str };
* };
*
*/
request.parse = {
'application/x-www-form-urlencoded': parseString,
'application/json': JSON.parse
};
/**
* Parse the given header `str` into
* an object containing the mapped fields.
*
* @param {String} str
* @return {Object}
* @api private
*/
function parseHeader(str) {
var lines = str.split(/\r?\n/);
var fields = {};
var index;
var line;
var field;
var val;
lines.pop(); // trailing CRLF
for (var i = 0, len = lines.length; i < len; ++i) {
line = lines[i];
index = line.indexOf(':');
field = line.slice(0, index).toLowerCase();
val = trim(line.slice(index + 1));
fields[field] = val;
}
return fields;
}
/**
* Return the mime type for the given `str`.
*
* @param {String} str
* @return {String}
* @api private
*/
function type(str){
return str.split(/ *; */).shift();
};
/**
* Return header field parameters.
*
* @param {String} str
* @return {Object}
* @api private
*/
function params(str){
return reduce(str.split(/ *; */), function(obj, str){
var parts = str.split(/ *= */)
, key = parts.shift()
, val = parts.shift();
if (key && val) obj[key] = val;
return obj;
}, {});
};
/**
* Initialize a new `Response` with the given `xhr`.
*
* - set flags (.ok, .error, etc)
* - parse header
*
* Examples:
*
* Aliasing `superagent` as `request` is nice:
*
* request = superagent;
*
* We can use the promise-like API, or pass callbacks:
*
* request.get('/').end(function(res){});
* request.get('/', function(res){});
*
* Sending data can be chained:
*
* request
* .post('/user')
* .send({ name: 'tj' })
* .end(function(res){});
*
* Or passed to `.send()`:
*
* request
* .post('/user')
* .send({ name: 'tj' }, function(res){});
*
* Or passed to `.post()`:
*
* request
* .post('/user', { name: 'tj' })
* .end(function(res){});
*
* Or further reduced to a single call for simple cases:
*
* request
* .post('/user', { name: 'tj' }, function(res){});
*
* @param {XMLHTTPRequest} xhr
* @param {Object} options
* @api private
*/
function Response(req, options) {
options = options || {};
this.req = req;
this.xhr = this.req.xhr;
// responseText is accessible only if responseType is '' or 'text' and on older browsers
this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr.responseType === 'undefined')
? this.xhr.responseText
: null;
this.statusText = this.req.xhr.statusText;
this.setStatusProperties(this.xhr.status);
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
// getResponseHeader still works. so we get content-type even if getting
// other headers fails.
this.header['content-type'] = this.xhr.getResponseHeader('content-type');
this.setHeaderProperties(this.header);
this.body = this.req.method != 'HEAD'
? this.parseBody(this.text ? this.text : this.xhr.response)
: null;
}
/**
* Get case-insensitive `field` value.
*
* @param {String} field
* @return {String}
* @api public
*/
Response.prototype.get = function(field){
return this.header[field.toLowerCase()];
};
/**
* Set header related properties:
*
* - `.type` the content type without params
*
* A response of "Content-Type: text/plain; charset=utf-8"
* will provide you with a `.type` of "text/plain".
*
* @param {Object} header
* @api private
*/
Response.prototype.setHeaderProperties = function(header){
// content-type
var ct = this.header['content-type'] || '';
this.type = type(ct);
// params
var obj = params(ct);
for (var key in obj) this[key] = obj[key];
};
/**
* Force given parser
*
* Sets the body parser no matter type.
*
* @param {Function}
* @api public
*/
Response.prototype.parse = function(fn){
this.parser = fn;
return this;
};
/**
* Parse the given body `str`.
*
* Used for auto-parsing of bodies. Parsers
* are defined on the `superagent.parse` object.
*
* @param {String} str
* @return {Mixed}
* @api private
*/
Response.prototype.parseBody = function(str){
var parse = this.parser || request.parse[this.type];
return parse && str && (str.length || str instanceof Object)
? parse(str)
: null;
};
/**
* Set flags such as `.ok` based on `status`.
*
* For example a 2xx response will give you a `.ok` of __true__
* whereas 5xx will be __false__ and `.error` will be __true__. The
* `.clientError` and `.serverError` are also available to be more
* specific, and `.statusType` is the class of error ranging from 1..5
* sometimes useful for mapping respond colors etc.
*
* "sugar" properties are also defined for common cases. Currently providing:
*
* - .noContent
* - .badRequest
* - .unauthorized
* - .notAcceptable
* - .notFound
*
* @param {Number} status
* @api private
*/
Response.prototype.setStatusProperties = function(status){
// handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
if (status === 1223) {
status = 204;
}
var type = status / 100 | 0;
// status / class
this.status = this.statusCode = status;
this.statusType = type;
// basics
this.info = 1 == type;
this.ok = 2 == type;
this.clientError = 4 == type;
this.serverError = 5 == type;
this.error = (4 == type || 5 == type)
? this.toError()
: false;
// sugar
this.accepted = 202 == status;
this.noContent = 204 == status;
this.badRequest = 400 == status;
this.unauthorized = 401 == status;
this.notAcceptable = 406 == status;
this.notFound = 404 == status;
this.forbidden = 403 == status;
};
/**
* Return an `Error` representative of this response.
*
* @return {Error}
* @api public
*/
Response.prototype.toError = function(){
var req = this.req;
var method = req.method;
var url = req.url;
var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')';
var err = new Error(msg);
err.status = this.status;
err.method = method;
err.url = url;
return err;
};
/**
* Expose `Response`.
*/
request.Response = Response;
/**
* Initialize a new `Request` with the given `method` and `url`.
*
* @param {String} method
* @param {String} url
* @api public
*/
function Request(method, url) {
var self = this;
Emitter.call(this);
this._query = this._query || [];
this.method = method;
this.url = url;
this.header = {};
this._header = {};
this.on('end', function(){
var err = null;
var res = null;
try {
res = new Response(self);
} catch(e) {
err = new Error('Parser is unable to parse the response');
err.parse = true;
err.original = e;
return self.callback(err);
}
self.emit('response', res);
if (err) {
return self.callback(err, res);
}
if (res.status >= 200 && res.status < 300) {
return self.callback(err, res);
}
var new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
new_err.original = err;
new_err.response = res;
new_err.status = res.status;
self.callback(new_err, res);
});
}
/**
* Mixin `Emitter`.
*/
Emitter(Request.prototype);
/**
* Allow for extension
*/
Request.prototype.use = function(fn) {
fn(this);
return this;
}
/**
* Set timeout to `ms`.
*
* @param {Number} ms
* @return {Request} for chaining
* @api public
*/
Request.prototype.timeout = function(ms){
this._timeout = ms;
return this;
};
/**
* Clear previous timeout.
*
* @return {Request} for chaining
* @api public
*/
Request.prototype.clearTimeout = function(){
this._timeout = 0;
clearTimeout(this._timer);
return this;
};
/**
* 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 header `field` to `val`, or multiple fields with one object.
*
* Examples:
*
* req.get('/')
* .set('Accept', 'application/json')
* .set('X-API-Key', 'foobar')
* .end(callback);
*
* req.get('/')
* .set({ Accept: 'application/json', 'X-API-Key': 'foobar' })
* .end(callback);
*
* @param {String|Object} field
* @param {String} val
* @return {Request} for chaining
* @api public
*/
Request.prototype.set = function(field, val){
if (isObject(field)) {
for (var key in field) {
this.set(key, field[key]);
}
return this;
}
this._header[field.toLowerCase()] = val;
this.header[field] = val;
return this;
};
/**
* Remove header `field`.
*
* Example:
*
* req.get('/')
* .unset('User-Agent')
* .end(callback);
*
* @param {String} field
* @return {Request} for chaining
* @api public
*/
Request.prototype.unset = function(field){
delete this._header[field.toLowerCase()];
delete this.header[field];
return this;
};
/**
* Get case-insensitive header `field` value.
*
* @param {String} field
* @return {String}
* @api private
*/
Request.prototype.getHeader = function(field){
return this._header[field.toLowerCase()];
};
/**
* Set Content-Type to `type`, mapping values from `request.types`.
*
* Examples:
*
* superagent.types.xml = 'application/xml';
*
* request.post('/')
* .type('xml')
* .send(xmlstring)
* .end(callback);
*
* request.post('/')
* .type('application/xml')
* .send(xmlstring)
* .end(callback);
*
* @param {String} type
* @return {Request} for chaining
* @api public
*/
Request.prototype.type = function(type){
this.set('Content-Type', request.types[type] || type);
return this;
};
/**
* Set Accept to `type`, mapping values from `request.types`.
*
* Examples:
*
* superagent.types.json = 'application/json';
*
* request.get('/agent')
* .accept('json')
* .end(callback);
*
* request.get('/agent')
* .accept('application/json')
* .end(callback);
*
* @param {String} accept
* @return {Request} for chaining
* @api public
*/
Request.prototype.accept = function(type){
this.set('Accept', request.types[type] || type);
return this;
};
/**
* Set Authorization field value with `user` and `pass`.
*
* @param {String} user
* @param {String} pass
* @return {Request} for chaining
* @api public
*/
Request.prototype.auth = function(user, pass){
var str = btoa(user + ':' + pass);
this.set('Authorization', 'Basic ' + str);
return this;
};
/**
* Add query-string `val`.
*
* Examples:
*
* request.get('/shoes')
* .query('size=10')
* .query({ color: 'blue' })
*
* @param {Object|String} val
* @return {Request} for chaining
* @api public
*/
Request.prototype.query = function(val){
if ('string' != typeof val) val = serialize(val);
if (val) this._query.push(val);
return this;
};
/**
* Write the field `name` and `val` for "multipart/form-data"
* request bodies.
*
* ``` js
* request.post('/upload')
* .field('foo', 'bar')
* .end(callback);
* ```
*
* @param {String} name
* @param {String|Blob|File} val
* @return {Request} for chaining
* @api public
*/
Request.prototype.field = function(name, val){
if (!this._formData) this._formData = new root.FormData();
this._formData.append(name, val);
return this;
};
/**
* Queue the given `file` as an attachment to the specified `field`,
* with optional `filename`.
*
* ``` js
* request.post('/upload')
* .attach(new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"}))
* .end(callback);
* ```
*
* @param {String} field
* @param {Blob|File} file
* @param {String} filename
* @return {Request} for chaining
* @api public
*/
Request.prototype.attach = function(field, file, filename){
if (!this._formData) this._formData = new root.FormData();
this._formData.append(field, file, filename);
return this;
};
/**
* Send `data`, defaulting the `.type()` to "json" when
* an object is given.
*
* Examples:
*
* // querystring
* request.get('/search')
* .end(callback)
*
* // multiple data "writes"
* request.get('/search')
* .send({ search: 'query' })
* .send({ range: '1..5' })
* .send({ order: 'desc' })
* .end(callback)
*
* // 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.getHeader('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.getHeader('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;
};
/**
* Invoke the callback with `err` and `res`
* and handle arity check.
*
* @param {Error} err
* @param {Response} res
* @api private
*/
Request.prototype.callback = function(err, res){
var fn = this._callback;
this.clearTimeout();
fn(err, res);
};
/**
* Invoke callback with x-domain error.
*
* @api private
*/
Request.prototype.crossDomainError = function(){
var err = new Error('Origin is not allowed by Access-Control-Allow-Origin');
err.crossDomain = true;
this.callback(err);
};
/**
* Invoke callback with timeout error.
*
* @api private
*/
Request.prototype.timeoutError = function(){
var timeout = this._timeout;
var err = new Error('timeout of ' + timeout + 'ms exceeded');
err.timeout = timeout;
this.callback(err);
};
/**
* 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;
};
/**
* Initiate request, invoking callback `fn(res)`
* with an instanceof `Response`.
*
* @param {Function} fn
* @return {Request} for chaining
* @api public
*/
Request.prototype.end = function(fn){
var self = this;
var xhr = this.xhr = request.getXHR();
var query = this._query.join('&');
var timeout = this._timeout;
var data = this._formData || this._data;
// store callback
this._callback = fn || noop;
// state change
xhr.onreadystatechange = function(){
if (4 != xhr.readyState) return;
// In IE9, reads to any property (e.g. status) off of an aborted XHR will
// result in the error "Could not complete the operation due to error c00c023f"
var status;
try { status = xhr.status } catch(e) { status = 0; }
if (0 == status) {
if (self.timedout) return self.timeoutError();
if (self.aborted) return;
return self.crossDomainError();
}
self.emit('end');
};
// progress
var handleProgress = function(e){
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
self.emit('progress', e);
};
if (this.hasListeners('progress')) {
xhr.onprogress = handleProgress;
}
try {
if (xhr.upload && this.hasListeners('progress')) {
xhr.upload.onprogress = handleProgress;
}
} catch(e) {
// Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
// Reported here:
// https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
}
// timeout
if (timeout && !this._timer) {
this._timer = setTimeout(function(){
self.timedout = true;
self.abort();
}, timeout);
}
// querystring
if (query) {
query = request.serializeObject(query);
this.url += ~this.url.indexOf('?')
? '&' + query
: '?' + query;
}
// initiate request
xhr.open(this.method, this.url, true);
// CORS
if (this._withCredentials) xhr.withCredentials = true;
// body
if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) {
// serialize stuff
var contentType = this.getHeader('Content-Type');
var serialize = request.serialize[contentType ? contentType.split(';')[0] : ''];
if (serialize) data = serialize(data);
}
// set header fields
for (var field in this.header) {
if (null == this.header[field]) continue;
xhr.setRequestHeader(field, this.header[field]);
}
// send stuff
this.emit('request', this);
xhr.send(data);
return this;
};
/**
* Faux promise support
*
* @param {Function} fulfill
* @param {Function} reject
* @return {Request}
*/
Request.prototype.then = function (fulfill, reject) {
return this.end(function(err, res) {
err ? reject(err) : fulfill(res);
});
}
/**
* Expose `Request`.
*/
request.Request = Request;
/**
* Issue a request:
*
* Examples:
*
* request('GET', '/users').end(callback)
* request('/users').end(callback)
* request('/users', callback)
*
* @param {String} method
* @param {String|Function} url or callback
* @return {Request}
* @api public
*/
function request(method, url) {
// callback
if ('function' == typeof url) {
return new Request('GET', method).end(url);
}
// url first
if (1 == arguments.length) {
return new Request('GET', method);
}
return new Request(method, url);
}
/**
* GET `url` with optional callback `fn(res)`.
*
* @param {String} url
* @param {Mixed|Function} data or fn
* @param {Function} fn
* @return {Request}
* @api public
*/
request.get = function(url, data, fn){
var req = request('GET', url);
if ('function' == typeof data) fn = data, data = null;
if (data) req.query(data);
if (fn) req.end(fn);
return req;
};
/**
* HEAD `url` with optional callback `fn(res)`.
*
* @param {String} url
* @param {Mixed|Function} data or fn
* @param {Function} fn
* @return {Request}
* @api public
*/
request.head = function(url, data, fn){
var req = request('HEAD', 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)`.
*
* @param {String} url
* @param {Function} fn
* @return {Request}
* @api public
*/
request.del = function(url, fn){
var req = request('DELETE', url);
if (fn) req.end(fn);
return req;
};
/**
* PATCH `url` with optional `data` and callback `fn(res)`.
*
* @param {String} url
* @param {Mixed} data
* @param {Function} fn
* @return {Request}
* @api public
*/
request.patch = function(url, data, fn){
var req = request('PATCH', url);
if ('function' == typeof data) fn = data, data = null;
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
/**
* POST `url` with optional `data` and callback `fn(res)`.
*
* @param {String} url
* @param {Mixed} data
* @param {Function} fn
* @return {Request}
* @api public
*/
request.post = function(url, data, fn){
var req = request('POST', url);
if ('function' == typeof data) fn = data, data = null;
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
/**
* PUT `url` with optional `data` and callback `fn(res)`.
*
* @param {String} url
* @param {Mixed|Function} data or fn
* @param {Function} fn
* @return {Request}
* @api public
*/
request.put = function(url, data, fn){
var req = request('PUT', url);
if ('function' == typeof data) fn = data, data = null;
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
/**
* Expose `request`.
*/
module.exports = request;
/***/ },
/* 3 */
/***/ function(module, exports) {
/**
* Expose `Emitter`.
*/
module.exports = Emitter;
/**
* Initialize a new `Emitter`.
*
* @api public
*/
function Emitter(obj) {
if (obj) return mixin(obj);
};
/**
* Mixin the emitter properties.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function mixin(obj) {
for (var key in Emitter.prototype) {
obj[key] = Emitter.prototype[key];
}
return obj;
}
/**
* Listen on the given `event` with `fn`.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.on =
Emitter.prototype.addEventListener = function(event, fn){
this._callbacks = this._callbacks || {};
(this._callbacks[event] = this._callbacks[event] || [])
.push(fn);
return this;
};
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.once = function(event, fn){
var self = this;
this._callbacks = this._callbacks || {};
function on() {
self.off(event, on);
fn.apply(this, arguments);
}
on.fn = fn;
this.on(event, on);
return this;
};
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.off =
Emitter.prototype.removeListener =
Emitter.prototype.removeAllListeners =
Emitter.prototype.removeEventListener = function(event, fn){
this._callbacks = this._callbacks || {};
// all
if (0 == arguments.length) {
this._callbacks = {};
return this;
}
// specific event
var callbacks = this._callbacks[event];
if (!callbacks) return this;
// remove all handlers
if (1 == arguments.length) {
delete this._callbacks[event];
return this;
}
// remove specific handler
var cb;
for (var i = 0; i < callbacks.length; i++) {
cb = callbacks[i];
if (cb === fn || cb.fn === fn) {
callbacks.splice(i, 1);
break;
}
}
return this;
};
/**
* Emit `event` with the given args.
*
* @param {String} event
* @param {Mixed} ...
* @return {Emitter}
*/
Emitter.prototype.emit = function(event){
this._callbacks = this._callbacks || {};
var args = [].slice.call(arguments, 1)
, callbacks = this._callbacks[event];
if (callbacks) {
callbacks = callbacks.slice(0);
for (var i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args);
}
}
return this;
};
/**
* Return array of callbacks for `event`.
*
* @param {String} event
* @return {Array}
* @api public
*/
Emitter.prototype.listeners = function(event){
this._callbacks = this._callbacks || {};
return this._callbacks[event] || [];
};
/**
* Check if this emitter has `event` handlers.
*
* @param {String} event
* @return {Boolean}
* @api public
*/
Emitter.prototype.hasListeners = function(event){
return !! this.listeners(event).length;
};
/***/ },
/* 4 */
/***/ function(module, exports) {
/**
* Reduce `arr` with `fn`.
*
* @param {Array} arr
* @param {Function} fn
* @param {Mixed} initial
*
* TODO: combatible error handling?
*/
module.exports = function(arr, fn, initial){
var idx = 0;
var len = arr.length;
var curr = arguments.length == 3
? initial
: arr[idx++];
while (idx < len) {
curr = fn.call(null, curr, arr[idx], ++idx, arr);
}
return curr;
};
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory){
'use strict';
/*istanbul ignore next:cant test*/
if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory();
} else if (true) {
// AMD. Register as an anonymous module.
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
} else {
// Browser globals
root.objectPath = factory();
}
})(this, function(){
'use strict';
var
toStr = Object.prototype.toString,
_hasOwnProperty = Object.prototype.hasOwnProperty;
function isEmpty(value){
if (!value) {
return true;
}
if (isArray(value) && value.length === 0) {
return true;
} else if (!isString(value)) {
for (var i in value) {
if (_hasOwnProperty.call(value, i)) {
return false;
}
}
return true;
}
return false;
}
function toString(type){
return toStr.call(type);
}
function isNumber(value){
return typeof value === 'number' || toString(value) === "[object Number]";
}
function isString(obj){
return typeof obj === 'string' || toString(obj) === "[object String]";
}
function isObject(obj){
return typeof obj === 'object' && toString(obj) === "[object Object]";
}
function isArray(obj){
return typeof obj === 'object' && typeof obj.length === 'number' && toString(obj) === '[object Array]';
}
function isBoolean(obj){
return typeof obj === 'boolean' || toString(obj) === '[object Boolean]';
}
function getKey(key){
var intKey = parseInt(key);
if (intKey.toString() === key) {
return intKey;
}
return key;
}
function set(obj, path, value, doNotReplace){
if (isNumber(path)) {
path = [path];
}
if (isEmpty(path)) {
return obj;
}
if (isString(path)) {
return set(obj, path.split('.').map(getKey), value, doNotReplace);
}
var currentPath = path[0];
if (path.length === 1) {
var oldVal = obj[currentPath];
if (oldVal === void 0 || !doNotReplace) {
obj[currentPath] = value;
}
return oldVal;
}
if (obj[currentPath] === void 0) {
//check if we assume an array
if(isNumber(path[1])) {
obj[currentPath] = [];
} else {
obj[currentPath] = {};
}
}
return set(obj[currentPath], path.slice(1), value, doNotReplace);
}
function del(obj, path) {
if (isNumber(path)) {
path = [path];
}
if (isEmpty(obj)) {
return void 0;
}
if (isEmpty(path)) {
return obj;
}
if(isString(path)) {
return del(obj, path.split('.'));
}
var currentPath = getKey(path[0]);
var oldVal = obj[currentPath];
if(path.length === 1) {
if (oldVal !== void 0) {
if (isArray(obj)) {
obj.splice(currentPath, 1);
} else {
delete obj[currentPath];
}
}
} else {
if (obj[currentPath] !== void 0) {
return del(obj[currentPath], path.slice(1));
}
}
return obj;
}
var objectPath = function(obj) {
return Object.keys(objectPath).reduce(function(proxy, prop) {
if (typeof objectPath[prop] === 'function') {
proxy[prop] = objectPath[prop].bind(objectPath, obj);
}
return proxy;
}, {});
};
objectPath.has = function (obj, path) {
if (isEmpty(obj)) {
return false;
}
if (isNumber(path)) {
path = [path];
} else if (isString(path)) {
path = path.split('.');
}
if (isEmpty(path) || path.length === 0) {
return false;
}
for (var i = 0; i < path.length; i++) {
var j = path[i];
if ((isObject(obj) || isArray(obj)) && _hasOwnProperty.call(obj, j)) {
obj = obj[j];
} else {
return false;
}
}
return true;
};
objectPath.ensureExists = function (obj, path, value){
return set(obj, path, value, true);
};
objectPath.set = function (obj, path, value, doNotReplace){
return set(obj, path, value, doNotReplace);
};
objectPath.insert = function (obj, path, value, at){
var arr = objectPath.get(obj, path);
at = ~~at;
if (!isArray(arr)) {
arr = [];
objectPath.set(obj, path, arr);
}
arr.splice(at, 0, value);
};
objectPath.empty = function(obj, path) {
if (isEmpty(path)) {
return obj;
}
if (isEmpty(obj)) {
return void 0;
}
var value, i;
if (!(value = objectPath.get(obj, path))) {
return obj;
}
if (isString(value)) {
return objectPath.set(obj, path, '');
} else if (isBoolean(value)) {
return objectPath.set(obj, path, false);
} else if (isNumber(value)) {
return objectPath.set(obj, path, 0);
} else if (isArray(value)) {
value.length = 0;
} else if (isObject(value)) {
for (i in value) {
if (_hasOwnProperty.call(value, i)) {
delete value[i];
}
}
} else {
return objectPath.set(obj, path, null);
}
};
objectPath.push = function (obj, path /*, values */){
var arr = objectPath.get(obj, path);
if (!isArray(arr)) {
arr = [];
objectPath.set(obj, path, arr);
}
arr.push.apply(arr, Array.prototype.slice.call(arguments, 2));
};
objectPath.coalesce = function (obj, paths, defaultValue) {
var value;
for (var i = 0, len = paths.length; i < len; i++) {
if ((value = objectPath.get(obj, paths[i])) !== void 0) {
return value;
}
}
return defaultValue;
};
objectPath.get = function (obj, path, defaultValue){
if (isNumber(path)) {
path = [path];
}
if (isEmpty(path)) {
return obj;
}
if (isEmpty(obj)) {
return defaultValue;
}
if (isString(path)) {
return objectPath.get(obj, path.split('.'), defaultValue);
}
var currentPath = getKey(path[0]);
if (path.length === 1) {
if (obj[currentPath] === void 0) {
return defaultValue;
}
return obj[currentPath];
}
return objectPath.get(obj[currentPath], path.slice(1), defaultValue);
};
objectPath.del = function(obj, path) {
return del(obj, path);
};
return objectPath;
});
/***/ },
/* 6 */
/***/ function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_6__;
/***/ },
/* 7 */
/***/ function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_7__;
/***/ },
/* 8 */
/***/ function(module, exports) {
"use strict";
exports.__esModule = true;
exports["default"] = clone;
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
module.exports = exports["default"];
/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports['default'] = deepEquals;
var _jsonHash = __webpack_require__(10);
function deepEquals(a, b) {
return a === b || _jsonHash.digest(a) === _jsonHash.digest(b);
}
module.exports = exports['default'];
/***/ },
/* 10 */
/***/ function(module, e