chainscript
Version:
Client for chainscript.io
373 lines (279 loc) • 10.5 kB
JavaScript
'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 = require('superagent');
var _superagent2 = _interopRequireDefault(_superagent);
var _objectPath = require('object-path');
var _objectPath2 = _interopRequireDefault(_objectPath);
var _bitcore = require('bitcore');
var _bitcoreMessage = require('bitcore-message');
var _bitcoreMessage2 = _interopRequireDefault(_bitcoreMessage);
var _utilsClone = require('./utils/clone');
var _utilsClone2 = _interopRequireDefault(_utilsClone);
var _utilsDeepEquals = require('./utils/deepEquals');
var _utilsDeepEquals2 = _interopRequireDefault(_utilsDeepEquals);
var _utilsPromisify = require('./utils/promisify');
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'];