eventric
Version:
behavior-first application development
1,617 lines (1,356 loc) • 97 kB
JavaScript
(function() {
'use strict';
var globals = typeof window === 'undefined' ? global : window;
if (typeof globals.require === 'function') return;
var _definedModules = {};
var _aliases = {};
var Module = {
_load: function(request, parent) {
var name = Module._resolveFilename(request, parent);
var definition = _definedModules[name];
if (!definition) throw new Error('Cannot find module "' + name + '" from '+ '"' + parent + '"');
if (Module._cache[name]) return Module._cache[name].exports;
var localRequire = createLocalRequire(name);
var module = {id: name, exports: {}};
Module._cache[name] = module;
definition.call(module.exports, module.exports, localRequire, module);
return module.exports;
},
_cache: {},
// TODO: Implement this to behave more like the Node environment
_resolveFilename: function(request, parent) {
var path = expand(dirname(parent), request);
if (_definedModules.hasOwnProperty(path)) return path;
path = expand(path, './index');
if (_definedModules.hasOwnProperty(path)) return path;
return request;
}
};
var require = function(name, loaderPath) {
return Module._load(name, loaderPath);
};
var expand = (function() {
var reg = /^\.\.?(\/|$)/;
return function(root, name) {
var results = [], parts, part;
parts = (reg.test(name) ? root + '/' + name : name).split('/');
for (var i = 0, length = parts.length; i < length; i++) {
part = parts[i];
if (part === '..') {
results.pop();
} else if (part !== '.' && part !== '') {
results.push(part);
}
}
return results.join('/');
};
})();
var createLocalRequire = function(parent) {
return function(name) {
return globals.require(name, parent);
};
};
var dirname = function(path) {
if (!path) return '';
return path.split('/').slice(0, -1).join('/');
};
require.register = require.define = function(bundle, fn) {
if (typeof bundle === 'object') {
for (var key in bundle) {
if (bundle.hasOwnProperty(key)) {
_definedModules[key] = bundle[key];
}
}
} else {
_definedModules[bundle] = fn;
}
};
require.list = function() {
var result = [];
for (var item in _definedModules) {
if (_definedModules.hasOwnProperty(item)) {
result.push(item);
}
}
return result;
};
globals.require = require;
require.define('module', function(exports, require, module) {
module.exports = Module;
});
})();
require.register("eventric/eventric", function(exports, require, module){
var Eventric,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__slice = [].slice;
Eventric = (function() {
function Eventric() {
this._handleRemoteRPCRequest = __bind(this._handleRemoteRPCRequest, this);
this.PubSub = require('./pub_sub');
this.EventBus = require('./event_bus');
this.Remote = require('./remote');
this.Context = require('./context');
this.DomainEvent = require('./domain_event');
this.Aggregate = require('./aggregate');
this.Repository = require('./repository');
this.Projection = require('./projection');
this.Logger = require('./logger');
this.RemoteInMemory = require('./remote/inmemory');
this.StoreInMemory = require('./store/inmemory');
this.log = this.Logger;
this._contexts = {};
this._params = {};
this._domainEventHandlers = {};
this._domainEventHandlersAll = [];
this._storeClasses = {};
this._remoteEndpoints = [];
this.addRemoteEndpoint('inmemory', this.RemoteInMemory.endpoint);
this.addStore('inmemory', this.StoreInMemory);
this.set('default domain events store', 'inmemory');
}
Eventric.prototype.set = function(key, value) {
return this._params[key] = value;
};
Eventric.prototype.get = function(key) {
if (!key) {
return this._params;
} else {
return this._params[key];
}
};
Eventric.prototype.addStore = function(storeName, StoreClass, storeOptions) {
if (storeOptions == null) {
storeOptions = {};
}
return this._storeClasses[storeName] = {
Class: StoreClass,
options: storeOptions
};
};
Eventric.prototype.getStores = function() {
return this._storeClasses;
};
Eventric.prototype.context = function(name) {
var context, err, pubsub;
if (!name) {
err = 'Contexts must have a name';
this.log.error(err);
throw new Error(err);
}
pubsub = new this.PubSub;
context = new this.Context(name, this);
this.mixin(context, pubsub);
this._delegateAllDomainEventsToGlobalHandlers(context);
this._delegateAllDomainEventsToRemoteEndpoints(context);
this._contexts[name] = context;
return context;
};
Eventric.prototype.getContext = function(name) {
return this._contexts[name];
};
Eventric.prototype.remote = function(contextName) {
var err, pubsub, remote;
if (!contextName) {
err = 'Missing context name';
this.log.error(err);
throw new Error(err);
}
pubsub = new this.PubSub;
remote = new this.Remote(contextName, this);
this.mixin(remote, pubsub);
return remote;
};
Eventric.prototype.addRemoteEndpoint = function(remoteName, remoteEndpoint) {
this._remoteEndpoints.push(remoteEndpoint);
return remoteEndpoint.setRPCHandler(this._handleRemoteRPCRequest);
};
Eventric.prototype._handleRemoteRPCRequest = function(request, callback) {
var context, error;
context = this.getContext(request.contextName);
if (!context) {
error = "Tried to handle Remote RPC with not registered context " + request.contextName;
this.log.error(error);
return callback(error, null);
}
if (this.Remote.ALLOWED_RPC_OPERATIONS.indexOf(request.method) === -1) {
error = "RPC operation '" + request.method + "' not allowed";
this.log.error(error);
return callback(error, null);
}
if (!(request.method in context)) {
error = "Remote RPC method " + request.method + " not found on Context " + request.contextName;
this.log.error(error);
return callback(error, null);
}
return context[request.method].apply(context, request.params).then(function(result) {
return callback(null, result);
})["catch"](function(error) {
return callback(error);
});
};
Eventric.prototype._delegateAllDomainEventsToGlobalHandlers = function(context) {
return context.subscribeToAllDomainEvents((function(_this) {
return function(domainEvent) {
var eventHandler, eventHandlers, _i, _len, _results;
eventHandlers = _this.getDomainEventHandlers(context.name, domainEvent.name);
_results = [];
for (_i = 0, _len = eventHandlers.length; _i < _len; _i++) {
eventHandler = eventHandlers[_i];
_results.push(eventHandler(domainEvent));
}
return _results;
};
})(this));
};
Eventric.prototype._delegateAllDomainEventsToRemoteEndpoints = function(context) {
return context.subscribeToAllDomainEvents((function(_this) {
return function(domainEvent) {
return _this._remoteEndpoints.forEach(function(remoteEndpoint) {
remoteEndpoint.publish(context.name, domainEvent.name, domainEvent);
if (domainEvent.aggregate) {
return remoteEndpoint.publish(context.name, domainEvent.name, domainEvent.aggregate.id, domainEvent);
}
});
};
})(this));
};
Eventric.prototype.subscribeToDomainEvent = function() {
var contextName, eventHandler, eventName, _arg, _base, _base1, _i;
_arg = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), eventHandler = arguments[_i++];
contextName = _arg[0], eventName = _arg[1];
if (contextName == null) {
contextName = 'all';
}
if (eventName == null) {
eventName = 'all';
}
if (contextName === 'all' && eventName === 'all') {
return this._domainEventHandlersAll.push(eventHandler);
} else {
if ((_base = this._domainEventHandlers)[contextName] == null) {
_base[contextName] = {};
}
if ((_base1 = this._domainEventHandlers[contextName])[eventName] == null) {
_base1[eventName] = [];
}
return this._domainEventHandlers[contextName][eventName].push(eventHandler);
}
};
Eventric.prototype.getDomainEventHandlers = function(contextName, domainEventName) {
var _ref, _ref1, _ref2, _ref3, _ref4;
return [].concat((_ref = (_ref1 = this._domainEventHandlers[contextName]) != null ? _ref1[domainEventName] : void 0) != null ? _ref : [], (_ref2 = (_ref3 = this._domainEventHandlers[contextName]) != null ? _ref3.all : void 0) != null ? _ref2 : [], (_ref4 = this._domainEventHandlersAll) != null ? _ref4 : []);
};
Eventric.prototype.generateUid = function(separator) {
var S4, delim;
S4 = function() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
delim = separator || "-";
return S4() + S4() + delim + S4() + delim + S4() + delim + S4() + delim + S4() + S4() + S4();
};
Eventric.prototype.defaults = function(options, optionDefaults) {
var allKeys, key, _i, _len;
allKeys = [].concat(Object.keys(options), Object.keys(optionDefaults));
for (_i = 0, _len = allKeys.length; _i < _len; _i++) {
key = allKeys[_i];
if (!options[key] && optionDefaults[key]) {
options[key] = optionDefaults[key];
}
}
return options;
};
Eventric.prototype.eachSeries = function(arr, iterator, callback) {
var completed, iterate;
callback = callback || function() {};
if (!Array.isArray(arr) || !arr.length) {
return callback();
}
completed = 0;
iterate = function() {
iterator(arr[completed], function(err) {
if (err) {
callback(err);
} else {
++completed;
if (completed >= arr.length) {
callback();
} else {
iterate();
}
}
});
};
return iterate();
};
Eventric.prototype.mixin = function(destination, source) {
var prop, _results;
_results = [];
for (prop in source) {
_results.push(destination[prop] = source[prop]);
}
return _results;
};
return Eventric;
})();
module.exports = Eventric;
});
require.register("es6-promise", function(exports, require, module){
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
* @version 2.0.1
*/
(function() {
"use strict";
function $$utils$$objectOrFunction(x) {
return typeof x === 'function' || (typeof x === 'object' && x !== null);
}
function $$utils$$isFunction(x) {
return typeof x === 'function';
}
function $$utils$$isMaybeThenable(x) {
return typeof x === 'object' && x !== null;
}
var $$utils$$_isArray;
if (!Array.isArray) {
$$utils$$_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
} else {
$$utils$$_isArray = Array.isArray;
}
var $$utils$$isArray = $$utils$$_isArray;
var $$utils$$now = Date.now || function() { return new Date().getTime(); };
function $$utils$$F() { }
var $$utils$$o_create = (Object.create || function (o) {
if (arguments.length > 1) {
throw new Error('Second argument not supported');
}
if (typeof o !== 'object') {
throw new TypeError('Argument must be an object');
}
$$utils$$F.prototype = o;
return new $$utils$$F();
});
var $$asap$$len = 0;
var $$asap$$default = function asap(callback, arg) {
$$asap$$queue[$$asap$$len] = callback;
$$asap$$queue[$$asap$$len + 1] = arg;
$$asap$$len += 2;
if ($$asap$$len === 2) {
// If len is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
$$asap$$scheduleFlush();
}
};
var $$asap$$browserGlobal = (typeof window !== 'undefined') ? window : {};
var $$asap$$BrowserMutationObserver = $$asap$$browserGlobal.MutationObserver || $$asap$$browserGlobal.WebKitMutationObserver;
// test for web worker but not in IE10
var $$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';
// node
function $$asap$$useNextTick() {
return function() {
process.nextTick($$asap$$flush);
};
}
function $$asap$$useMutationObserver() {
var iterations = 0;
var observer = new $$asap$$BrowserMutationObserver($$asap$$flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
// web worker
function $$asap$$useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = $$asap$$flush;
return function () {
channel.port2.postMessage(0);
};
}
function $$asap$$useSetTimeout() {
return function() {
setTimeout($$asap$$flush, 1);
};
}
var $$asap$$queue = new Array(1000);
function $$asap$$flush() {
for (var i = 0; i < $$asap$$len; i+=2) {
var callback = $$asap$$queue[i];
var arg = $$asap$$queue[i+1];
callback(arg);
$$asap$$queue[i] = undefined;
$$asap$$queue[i+1] = undefined;
}
$$asap$$len = 0;
}
var $$asap$$scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
$$asap$$scheduleFlush = $$asap$$useNextTick();
} else if ($$asap$$BrowserMutationObserver) {
$$asap$$scheduleFlush = $$asap$$useMutationObserver();
} else if ($$asap$$isWorker) {
$$asap$$scheduleFlush = $$asap$$useMessageChannel();
} else {
$$asap$$scheduleFlush = $$asap$$useSetTimeout();
}
function $$$internal$$noop() {}
var $$$internal$$PENDING = void 0;
var $$$internal$$FULFILLED = 1;
var $$$internal$$REJECTED = 2;
var $$$internal$$GET_THEN_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$selfFullfillment() {
return new TypeError("You cannot resolve a promise with itself");
}
function $$$internal$$cannotReturnOwn() {
return new TypeError('A promises callback cannot return that same promise.')
}
function $$$internal$$getThen(promise) {
try {
return promise.then;
} catch(error) {
$$$internal$$GET_THEN_ERROR.error = error;
return $$$internal$$GET_THEN_ERROR;
}
}
function $$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try {
then.call(value, fulfillmentHandler, rejectionHandler);
} catch(e) {
return e;
}
}
function $$$internal$$handleForeignThenable(promise, thenable, then) {
$$asap$$default(function(promise) {
var sealed = false;
var error = $$$internal$$tryThen(then, thenable, function(value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
$$$internal$$resolve(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}, function(reason) {
if (sealed) { return; }
sealed = true;
$$$internal$$reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));
if (!sealed && error) {
sealed = true;
$$$internal$$reject(promise, error);
}
}, promise);
}
function $$$internal$$handleOwnThenable(promise, thenable) {
if (thenable._state === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, thenable._result);
} else if (promise._state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, thenable._result);
} else {
$$$internal$$subscribe(thenable, undefined, function(value) {
$$$internal$$resolve(promise, value);
}, function(reason) {
$$$internal$$reject(promise, reason);
});
}
}
function $$$internal$$handleMaybeThenable(promise, maybeThenable) {
if (maybeThenable.constructor === promise.constructor) {
$$$internal$$handleOwnThenable(promise, maybeThenable);
} else {
var then = $$$internal$$getThen(maybeThenable);
if (then === $$$internal$$GET_THEN_ERROR) {
$$$internal$$reject(promise, $$$internal$$GET_THEN_ERROR.error);
} else if (then === undefined) {
$$$internal$$fulfill(promise, maybeThenable);
} else if ($$utils$$isFunction(then)) {
$$$internal$$handleForeignThenable(promise, maybeThenable, then);
} else {
$$$internal$$fulfill(promise, maybeThenable);
}
}
}
function $$$internal$$resolve(promise, value) {
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$selfFullfillment());
} else if ($$utils$$objectOrFunction(value)) {
$$$internal$$handleMaybeThenable(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}
function $$$internal$$publishRejection(promise) {
if (promise._onerror) {
promise._onerror(promise._result);
}
$$$internal$$publish(promise);
}
function $$$internal$$fulfill(promise, value) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._result = value;
promise._state = $$$internal$$FULFILLED;
if (promise._subscribers.length === 0) {
} else {
$$asap$$default($$$internal$$publish, promise);
}
}
function $$$internal$$reject(promise, reason) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._state = $$$internal$$REJECTED;
promise._result = reason;
$$asap$$default($$$internal$$publishRejection, promise);
}
function $$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;
parent._onerror = null;
subscribers[length] = child;
subscribers[length + $$$internal$$FULFILLED] = onFulfillment;
subscribers[length + $$$internal$$REJECTED] = onRejection;
if (length === 0 && parent._state) {
$$asap$$default($$$internal$$publish, parent);
}
}
function $$$internal$$publish(promise) {
var subscribers = promise._subscribers;
var settled = promise._state;
if (subscribers.length === 0) { return; }
var child, callback, detail = promise._result;
for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];
if (child) {
$$$internal$$invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}
promise._subscribers.length = 0;
}
function $$$internal$$ErrorObject() {
this.error = null;
}
var $$$internal$$TRY_CATCH_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$tryCatch(callback, detail) {
try {
return callback(detail);
} catch(e) {
$$$internal$$TRY_CATCH_ERROR.error = e;
return $$$internal$$TRY_CATCH_ERROR;
}
}
function $$$internal$$invokeCallback(settled, promise, callback, detail) {
var hasCallback = $$utils$$isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
value = $$$internal$$tryCatch(callback, detail);
if (value === $$$internal$$TRY_CATCH_ERROR) {
failed = true;
error = value.error;
value = null;
} else {
succeeded = true;
}
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$cannotReturnOwn());
return;
}
} else {
value = detail;
succeeded = true;
}
if (promise._state !== $$$internal$$PENDING) {
// noop
} else if (hasCallback && succeeded) {
$$$internal$$resolve(promise, value);
} else if (failed) {
$$$internal$$reject(promise, error);
} else if (settled === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, value);
} else if (settled === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
}
}
function $$$internal$$initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
$$$internal$$resolve(promise, value);
}, function rejectPromise(reason) {
$$$internal$$reject(promise, reason);
});
} catch(e) {
$$$internal$$reject(promise, e);
}
}
function $$$enumerator$$makeSettledResult(state, position, value) {
if (state === $$$internal$$FULFILLED) {
return {
state: 'fulfilled',
value: value
};
} else {
return {
state: 'rejected',
reason: value
};
}
}
function $$$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
this._instanceConstructor = Constructor;
this.promise = new Constructor($$$internal$$noop, label);
this._abortOnReject = abortOnReject;
if (this._validateInput(input)) {
this._input = input;
this.length = input.length;
this._remaining = input.length;
this._init();
if (this.length === 0) {
$$$internal$$fulfill(this.promise, this._result);
} else {
this.length = this.length || 0;
this._enumerate();
if (this._remaining === 0) {
$$$internal$$fulfill(this.promise, this._result);
}
}
} else {
$$$internal$$reject(this.promise, this._validationError());
}
}
$$$enumerator$$Enumerator.prototype._validateInput = function(input) {
return $$utils$$isArray(input);
};
$$$enumerator$$Enumerator.prototype._validationError = function() {
return new Error('Array Methods must be provided an Array');
};
$$$enumerator$$Enumerator.prototype._init = function() {
this._result = new Array(this.length);
};
var $$$enumerator$$default = $$$enumerator$$Enumerator;
$$$enumerator$$Enumerator.prototype._enumerate = function() {
var length = this.length;
var promise = this.promise;
var input = this._input;
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
this._eachEntry(input[i], i);
}
};
$$$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
var c = this._instanceConstructor;
if ($$utils$$isMaybeThenable(entry)) {
if (entry.constructor === c && entry._state !== $$$internal$$PENDING) {
entry._onerror = null;
this._settledAt(entry._state, i, entry._result);
} else {
this._willSettleAt(c.resolve(entry), i);
}
} else {
this._remaining--;
this._result[i] = this._makeResult($$$internal$$FULFILLED, i, entry);
}
};
$$$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
var promise = this.promise;
if (promise._state === $$$internal$$PENDING) {
this._remaining--;
if (this._abortOnReject && state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
} else {
this._result[i] = this._makeResult(state, i, value);
}
}
if (this._remaining === 0) {
$$$internal$$fulfill(promise, this._result);
}
};
$$$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
return value;
};
$$$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
var enumerator = this;
$$$internal$$subscribe(promise, undefined, function(value) {
enumerator._settledAt($$$internal$$FULFILLED, i, value);
}, function(reason) {
enumerator._settledAt($$$internal$$REJECTED, i, reason);
});
};
var $$promise$all$$default = function all(entries, label) {
return new $$$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
};
var $$promise$race$$default = function race(entries, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
if (!$$utils$$isArray(entries)) {
$$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
return promise;
}
var length = entries.length;
function onFulfillment(value) {
$$$internal$$resolve(promise, value);
}
function onRejection(reason) {
$$$internal$$reject(promise, reason);
}
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
$$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
}
return promise;
};
var $$promise$resolve$$default = function resolve(object, label) {
/*jshint validthis:true */
var Constructor = this;
if (object && typeof object === 'object' && object.constructor === Constructor) {
return object;
}
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$resolve(promise, object);
return promise;
};
var $$promise$reject$$default = function reject(reason, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$reject(promise, reason);
return promise;
};
var $$es6$promise$promise$$counter = 0;
function $$es6$promise$promise$$needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}
function $$es6$promise$promise$$needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}
var $$es6$promise$promise$$default = $$es6$promise$promise$$Promise;
/**
Promise objects represent the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its `then` method, which
registers callbacks to receive either a promise’s eventual value or the reason
why the promise cannot be fulfilled.
Terminology
-----------
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
- `thenable` is an object or function that defines a `then` method.
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
- `exception` is a value that is thrown using the throw statement.
- `reason` is a value that indicates why a promise was rejected.
- `settled` the final resting state of a promise, fulfilled or rejected.
A promise can be in one of three states: pending, fulfilled, or rejected.
Promises that are fulfilled have a fulfillment value and are in the fulfilled
state. Promises that are rejected have a rejection reason and are in the
rejected state. A fulfillment value is never a thenable.
Promises can also be said to *resolve* a value. If this value is also a
promise, then the original promise's settled state will match the value's
settled state. So a promise that *resolves* a promise that rejects will
itself reject, and a promise that *resolves* a promise that fulfills will
itself fulfill.
Basic Usage:
------------
```js
var promise = new Promise(function(resolve, reject) {
// on success
resolve(value);
// on failure
reject(reason);
});
promise.then(function(value) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Advanced Usage:
---------------
Promises shine when abstracting away asynchronous interactions such as
`XMLHttpRequest`s.
```js
function getJSON(url) {
return new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
}
}
};
});
}
getJSON('/posts.json').then(function(json) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Unlike callbacks, promises are great composable primitives.
```js
Promise.all([
getJSON('/posts'),
getJSON('/comments')
]).then(function(values){
values[0] // => postsJSON
values[1] // => commentsJSON
return values;
});
```
@class Promise
@param {function} resolver
Useful for tooling.
@constructor
*/
function $$es6$promise$promise$$Promise(resolver) {
this._id = $$es6$promise$promise$$counter++;
this._state = undefined;
this._result = undefined;
this._subscribers = [];
if ($$$internal$$noop !== resolver) {
if (!$$utils$$isFunction(resolver)) {
$$es6$promise$promise$$needsResolver();
}
if (!(this instanceof $$es6$promise$promise$$Promise)) {
$$es6$promise$promise$$needsNew();
}
$$$internal$$initializePromise(this, resolver);
}
}
$$es6$promise$promise$$Promise.all = $$promise$all$$default;
$$es6$promise$promise$$Promise.race = $$promise$race$$default;
$$es6$promise$promise$$Promise.resolve = $$promise$resolve$$default;
$$es6$promise$promise$$Promise.reject = $$promise$reject$$default;
$$es6$promise$promise$$Promise.prototype = {
constructor: $$es6$promise$promise$$Promise,
/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.
```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```
Chaining
--------
The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.
```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});
findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```
Assimilation
------------
Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```
If the assimliated promise rejects, then the downstream promise will also reject.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```
Simple Example
--------------
Synchronous Example
```javascript
var result;
try {
result = findResult();
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```
Promise Example;
```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```
Advanced Example
--------------
Synchronous Example
```javascript
var author, books;
try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
function foundBooks(books) {
}
function failure(reason) {
}
findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```
Promise Example;
```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```
@method then
@param {Function} onFulfilled
@param {Function} onRejected
Useful for tooling.
@return {Promise}
*/
then: function(onFulfillment, onRejection) {
var parent = this;
var state = parent._state;
if (state === $$$internal$$FULFILLED && !onFulfillment || state === $$$internal$$REJECTED && !onRejection) {
return this;
}
var child = new this.constructor($$$internal$$noop);
var result = parent._result;
if (state) {
var callback = arguments[state - 1];
$$asap$$default(function(){
$$$internal$$invokeCallback(state, child, callback, result);
});
} else {
$$$internal$$subscribe(parent, child, onFulfillment, onRejection);
}
return child;
},
/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.
```js
function findAuthor(){
throw new Error('couldn't find that author');
}
// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}
// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```
@method catch
@param {Function} onRejection
Useful for tooling.
@return {Promise}
*/
'catch': function(onRejection) {
return this.then(null, onRejection);
}
};
var $$es6$promise$polyfill$$default = function polyfill() {
var local;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof window !== 'undefined' && window.document) {
local = window;
} else {
local = self;
}
var es6PromiseSupport =
"Promise" in local &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
"resolve" in local.Promise &&
"reject" in local.Promise &&
"all" in local.Promise &&
"race" in local.Promise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
(function() {
var resolve;
new local.Promise(function(r) { resolve = r; });
return $$utils$$isFunction(resolve);
}());
if (!es6PromiseSupport) {
local.Promise = $$es6$promise$promise$$default;
}
};
var es6$promise$umd$$ES6Promise = {
'Promise': $$es6$promise$promise$$default,
'polyfill': $$es6$promise$polyfill$$default
};
/* global define:true module:true window: true */
if (typeof define === 'function' && define['amd']) {
define(function() { return es6$promise$umd$$ES6Promise; });
} else if (typeof module !== 'undefined' && module['exports']) {
module['exports'] = es6$promise$umd$$ES6Promise;
} else if (typeof this !== 'undefined') {
this['ES6Promise'] = es6$promise$umd$$ES6Promise;
}
}).call(this);
});
require.register("eventric/index", function(exports, require, module){
require('es6-promise').polyfill();
module.exports = new (require('./eventric'));
});
require.register("eventric/aggregate/aggregate", function(exports, require, module){
var Aggregate,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Aggregate = (function() {
function Aggregate(_context, _eventric, _name, Root) {
this._context = _context;
this._eventric = _eventric;
this._name = _name;
this.getDomainEvents = __bind(this.getDomainEvents, this);
this.emitDomainEvent = __bind(this.emitDomainEvent, this);
this._domainEvents = [];
if (!Root) {
this.root = {};
} else {
this.root = new Root;
}
this.root.$emitDomainEvent = this.emitDomainEvent;
}
Aggregate.prototype.emitDomainEvent = function(domainEventName, domainEventPayload) {
var DomainEventClass, domainEvent, err;
DomainEventClass = this._context.getDomainEvent(domainEventName);
if (!DomainEventClass) {
err = "Tried to emitDomainEvent '" + domainEventName + "' which is not defined";
this._eventric.log.error(err);
throw new Error(err);
}
domainEvent = this._createDomainEvent(domainEventName, DomainEventClass, domainEventPayload);
this._domainEvents.push(domainEvent);
this._handleDomainEvent(domainEventName, domainEvent);
return this._eventric.log.debug("Created and Handled DomainEvent in Aggregate", domainEvent);
};
Aggregate.prototype._createDomainEvent = function(domainEventName, DomainEventClass, domainEventPayload) {
var payload;
payload = {};
DomainEventClass.apply(payload, [domainEventPayload]);
return new this._eventric.DomainEvent({
id: this._eventric.generateUid(),
name: domainEventName,
aggregate: {
id: this.id,
name: this._name
},
context: this._context.name,
payload: payload
});
};
Aggregate.prototype._handleDomainEvent = function(domainEventName, domainEvent) {
if (this.root["handle" + domainEventName]) {
return this.root["handle" + domainEventName](domainEvent, function() {});
} else {
return this._eventric.log.debug("Tried to handle the DomainEvent '" + domainEventName + "' without a matching handle method");
}
};
Aggregate.prototype.getDomainEvents = function() {
return this._domainEvents;
};
Aggregate.prototype.applyDomainEvents = function(domainEvents) {
var domainEvent, _i, _len, _results;
_results = [];
for (_i = 0, _len = domainEvents.length; _i < _len; _i++) {
domainEvent = domainEvents[_i];
_results.push(this._applyDomainEvent(domainEvent));
}
return _results;
};
Aggregate.prototype._applyDomainEvent = function(domainEvent) {
return this._handleDomainEvent(domainEvent.name, domainEvent);
};
return Aggregate;
})();
module.exports = Aggregate;
});
require.register("eventric/aggregate/index", function(exports, require, module){
module.exports = require('./aggregate');
});
require.register("eventric/context/context", function(exports, require, module){
var Context,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__slice = [].slice;
Context = (function() {
function Context(name, _eventric) {
this.name = name;
this._eventric = _eventric;
this.clearProjectionStore = __bind(this.clearProjectionStore, this);
this.getProjectionStore = __bind(this.getProjectionStore, this);
this._getAggregateRepository = __bind(this._getAggregateRepository, this);
this.publishDomainEvent = __bind(this.publishDomainEvent, this);
this.emitDomainEvent = __bind(this.emitDomainEvent, this);
this._initialized = false;
this._params = this._eventric.get();
this._di = {};
this._aggregateRootClasses = {};
this._commandHandlers = {};
this._queryHandlers = {};
this._domainEventClasses = {};
this._domainEventHandlers = {};
this._projectionClasses = {};
this._domainEventStreamClasses = {};
this._domainEventStreamInstances = {};
this._repositoryInstances = {};
this._storeClasses = {};
this._storeInstances = {};
this._eventBus = new this._eventric.EventBus(this._eventric);
this.projectionService = new this._eventric.Projection(this._eventric);
this.log = this._eventric.log;
}
Context.prototype.set = function(key, value) {
this._params[key] = value;
return this;
};
Context.prototype.get = function(key) {
return this._params[key];
};
Context.prototype.emitDomainEvent = function(domainEventName, domainEventPayload) {
var DomainEventClass, domainEvent;
DomainEventClass = this.getDomainEvent(domainEventName);
if (!DomainEventClass) {
throw new Error("Tried to emitDomainEvent '" + domainEventName + "' which is not defined");
}
domainEvent = this._createDomainEvent(domainEventName, DomainEventClass, domainEventPayload);
return this.saveAndPublishDomainEvent(domainEvent).then((function(_this) {
return function() {
return _this._eventric.log.debug("Created and Handled DomainEvent in Context", domainEvent);
};
})(this));
};
Context.prototype.publishDomainEvent = function(domainEvent) {
return this._eventBus.publishDomainEvent(domainEvent);
};
Context.prototype._createDomainEvent = function(domainEventName, DomainEventClass, domainEventPayload) {
return new this._eventric.DomainEvent({
id: this._eventric.generateUid(),
name: domainEventName,
context: this.name,
payload: new DomainEventClass(domainEventPayload)
});
};
Context.prototype.addStore = function(storeName, StoreClass, storeOptions) {
if (storeOptions == null) {
storeOptions = {};
}
this._storeClasses[storeName] = {
Class: StoreClass,
options: storeOptions
};
return this;
};
Context.prototype.defineDomainEvent = function(domainEventName, DomainEventClass) {
this._domainEventClasses[domainEventName] = DomainEventClass;
return this;
};
Context.prototype.defineDomainEvents = function(domainEventClassesObj) {
var DomainEventClass, domainEventName;
for (domainEventName in domainEventClassesObj) {
DomainEventClass = domainEventClassesObj[domainEventName];
this.defineDomainEvent(domainEventName, DomainEventClass);
}
return this;
};
Context.prototype.addCommandHandler = function(commandHandlerName, commandHandlerFn) {
this._commandHandlers[commandHandlerName] = commandHandlerFn;
return this;
};
Context.prototype._getAggregateRepository = function(aggregateName, command) {
var AggregateRoot, repositoriesCache, repository;
if (!repositoriesCache) {
repositoriesCache = {};
}
if (!repositoriesCache[aggregateName]) {
AggregateRoot = this._aggregateRootClasses[aggregateName];
repository = new this._eventric.Repository({
aggregateName: aggregateName,
AggregateRoot: AggregateRoot,
context: this,
eventric: this._eventric
});
repositoriesCache[aggregateName] = repository;
}
repositoriesCache[aggregateName].setCommand(command);
return repositoriesCache[aggregateName];
};
Context.prototype.addCommandHandlers = function(commandObj) {
var commandFunction, commandHandlerName;
for (commandHandlerName in commandObj) {
commandFunction = commandObj[commandHandlerName];
this.addCommandHandler(commandHandlerName, commandFunction);
}
return this;
};
Context.prototype.addQueryHandler = function(queryHandlerName, queryHandlerFn) {
this._queryHandlers[queryHandlerName] = queryHandlerFn;
return this;
};
Context.prototype.addQueryHandlers = function(queryObj) {
var queryFunction, queryHandlerName;
for (queryHandlerName in queryObj) {
queryFunction = queryObj[queryHandlerName];
this.addQueryHandler(queryHandlerName, queryFunction);
}
return this;
};
Context.prototype.addAggregate = function(aggregateName, AggregateRootClass) {
this._aggregateRootClasses[aggregateName] = AggregateRootClass;
return this;
};
Context.prototype.addAggregates = function(aggregatesObj) {
var AggregateRootClass, aggregateName;
for (aggregateName in aggregatesObj) {
AggregateRootClass = aggregatesObj[aggregateName];
this.addAggregate(aggregateName, AggregateRootClass);
}
return this;
};
Context.prototype.subscribeToDomainEvent = function(domainEventName, handlerFn) {
var domainEventHandler;
domainEventHandler = (function(_this) {
return function() {
return handlerFn.apply(_this._di, arguments);
};
})(this);
return this._eventBus.subscribeToDomainEvent(domainEventName, domainEventHandler);
};
Context.prototype.subscribeToDomainEvents = function(domainEventHandlersObj) {
var domainEventName, handlerFn, _results;
_results = [];
for (domainEventName in domainEventHandlersObj) {
handlerFn = domainEventHandlersObj[domainEventName];
_results.push(this.subscribeToDomainEvent(domainEventName, handlerFn));
}
return _results;
};
Context.prototype.subscribeToDomainEventWithAggregateId = function(domainEventName, aggregateId, handlerFn) {
var domainEventHandler;
domainEventHandler = (function(_this) {
return function() {
return handlerFn.apply(_this._di, arguments);
};
})(this);
return this._eventBus.subscribeToDomainEventWithAggregateId(domainEventName, aggregateId, domainEventHandler);
};
Context.prototype.subscribeToAllDomainEvents = function(handlerFn) {
var domainEventHandler;
domainEventHandler = (function(_this) {
return function() {
return handlerFn.apply(_this._di, arguments);
};
})(this);
return this._eventBus.subscribeToAllDomainEvents(domainEventHandler);
};
Context.prototype.addProjection = function(projectionName, ProjectionClass) {
this._projectionClasses[projectionName] = ProjectionClass;
return this;
};
Context.prototype.addProjections = function(viewsObj) {
var ProjectionClass, projectionName;
for (projectionName in viewsObj) {
ProjectionClass = viewsObj[projectionName];
this.addProjection(projectionName, ProjectionClass);
}
return this;
};
Context.prototype.getProjectionInstance = function(projectionId) {
return this.projectionService.getInstance(projectionId);
};
Context.prototype.destroyProjectionInstance = function(projectionId) {
return this.projectionService.destroyInstance(projectionId, this);
};
Context.prototype.initializeProjectionInstance = function(projectionName, params)