fh-wfm-mediator
Advanced tools
Comparing version 0.1.0-rc3 to 0.2.0-rc1
@@ -1,27 +0,30 @@ | ||
'use strict'; | ||
var mediator = require('../mediator'); | ||
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var angular = require("angular"); | ||
var mediator_1 = require("../mediator"); | ||
exports.mediator = mediator_1.default; | ||
angular.module('wfm.core.mediator', ['ng']) | ||
.factory('mediator', function mediatorService($q) { | ||
var originalRequest = mediator.request; | ||
// monkey patch the request function, wrapping the returned promise as an angular promise | ||
mediator.request = function() { | ||
var promise = originalRequest.apply(mediator, arguments); | ||
return $q.when(promise); | ||
}; | ||
mediator.subscribeForScope = function(topic,scope,fn) { | ||
var subscriber = mediator.subscribe(topic,fn); | ||
scope.$on("$destroy", function() { | ||
mediator.remove(topic, subscriber.id); | ||
}); | ||
}; | ||
return mediator; | ||
.factory('mediator', function mediatorService($q) { | ||
var originalRequest = mediator_1.default.request; | ||
// monkey patch the request function, wrapping the returned promise as an angular promise | ||
mediator_1.default.request = function () { | ||
var promise = originalRequest.apply(mediator_1.default, arguments); | ||
return $q.when(promise); | ||
}; | ||
mediator_1.default.subscribeForScope = function (topic, scope, fn) { | ||
var subscriber = mediator_1.default.subscribe(topic, fn); | ||
scope.$on('$destroy', function () { | ||
mediator_1.default.remove(topic, subscriber.id); | ||
}); | ||
return subscriber; | ||
}; | ||
return mediator_1.default; | ||
}); | ||
module.exports = 'wfm.core.mediator'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = 'wfm.core.mediator'; | ||
__export(require("../mediator")); | ||
var topics_1 = require("../topics"); | ||
exports.Topics = topics_1.default; | ||
//# sourceMappingURL=mediator-ng.js.map |
@@ -1,105 +0,108 @@ | ||
'use strict'; | ||
var _ = require('lodash'); | ||
var Mediator = require('mediator-js').Mediator; | ||
var Promise = require('bluebird'); | ||
/** | ||
* A version of {@link once} that returns a Promise | ||
* @param {String} channel Channel identifier to wait on a single message | ||
* @return {Promise} A promise that is fulfilled with the next published | ||
* message in the channel | ||
*/ | ||
Mediator.prototype.promise = function(channel, options, context) { | ||
var self = this; | ||
return new Promise(function(resolve) { | ||
self.once(channel, resolve, options, context); | ||
}); | ||
"use strict"; | ||
var __extends = (this && this.__extends) || function (d, b) { | ||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
/** | ||
* Publishes a message on a topic and wait for a response or error | ||
* | ||
* By convention 'return' topics are prefixed with 'done:' and 'error:' to signal | ||
* the result of the operation, and suffixed with a unique id to map clients in | ||
* order to supply the results to the correct client. | ||
* | ||
* @param {String} topic Channel identifier to publish the initial message | ||
* | ||
* @param {Any} parameters The data to publish to the topic. The unique id used to publish | ||
* the 'return' topic is extracted from this parameter according to | ||
* the following rules: | ||
* - `parameters.id` property, If parameters has this property | ||
* - `parameters[0]` if parameters is an Array | ||
* - `parameters.toString()` otherwise | ||
* | ||
* @param {Object} options Options object | ||
* @param {String} options.uid Overrides the unique id from the {@link parameters} | ||
* @param {String} options.doneTopic Base topic to subscribe for the result of the request, | ||
* gets prefixed with 'done:' | ||
* @param {String} options.errorTopic Base topic to subscribe for errors on the request, | ||
* gets prefixed with 'error:' | ||
* | ||
* @return {Promise} A Promise that gets fulfilled with the result of the request | ||
* or rejected with the error from the above topics | ||
*/ | ||
Mediator.prototype.request = function(topic, parameters, options) { | ||
var self = this; | ||
options = options || {}; | ||
var topics = { | ||
request: topic, | ||
done: options.doneTopic || 'done:' + topic, | ||
error: options.errorTopic || 'error:' + topic | ||
}; | ||
var subs = {}; | ||
var uid = null; | ||
if (_.has(options, 'uid')) { | ||
uid = options.uid; | ||
} else if (typeof parameters !== "undefined" && parameters !== null) { | ||
if (_.has(parameters, 'id')) { | ||
uid = parameters.id; | ||
} else { | ||
uid = parameters instanceof Array ? parameters[0] : parameters.toString(); | ||
var Promise = require("bluebird"); | ||
var _ = require("lodash"); | ||
var mediatorJs = require("mediator-js"); | ||
exports.BaseMediator = mediatorJs.Mediator; | ||
var Mediator = (function (_super) { | ||
__extends(Mediator, _super); | ||
function Mediator() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
} | ||
if (uid !== null) { | ||
topics.done += ':' + uid; | ||
topics.error += ':' + uid; | ||
} | ||
if (!options.timeout) { | ||
options.timeout = 2000; | ||
} | ||
function unsubscribe() { | ||
self.remove(topics.done, subs.done.id); | ||
self.remove(topics.error, subs.error.id); | ||
} | ||
var args = [topics.request]; | ||
if (parameters instanceof Array) { | ||
Array.prototype.push.apply(args, parameters); | ||
} else { | ||
args.push(parameters); | ||
} | ||
self.publish.apply(mediator, args); | ||
return new Promise(function(resolve, reject) { | ||
subs.done = self.once(topics.done, resolve); | ||
subs.error = mediator.once(topics.error, reject); | ||
}) | ||
.timeout(options.timeout, new Error('Mediator request timeout for topic ' + topic)) | ||
.tap(unsubscribe) | ||
.catch(function(e) { | ||
unsubscribe(); | ||
// still forward the rejection to clients | ||
throw e; | ||
}); | ||
}; | ||
/** | ||
* A version of {@link once} that returns a Promise | ||
* @param {String} channel Channel identifier to wait on a single message | ||
* @return {Promise} A promise that is fulfilled with the next published | ||
* message in the channel | ||
*/ | ||
Mediator.prototype.promise = function (channel, options, context) { | ||
var self = this; | ||
return new Promise(function (resolve) { | ||
self.once(channel, resolve, options, context); | ||
}); | ||
}; | ||
; | ||
/** | ||
* Publishes a message on a topic and wait for a response or error | ||
* | ||
* By convention 'return' topics are prefixed with 'done:' and 'error:' to signal | ||
* the result of the operation, and suffixed with a unique id to map clients in | ||
* order to supply the results to the correct client. | ||
* | ||
* @param {String} topic Channel identifier to publish the initial message | ||
* | ||
* @param {Any} parameters The data to publish to the topic. The unique id used to publish | ||
* the 'return' topic is extracted from this parameter according to | ||
* the following rules: | ||
* - `parameters.id` property, If parameters has this property | ||
* - `parameters[0]` if parameters is an Array | ||
* - `parameters.toString()` otherwise | ||
* | ||
* @param {Object} options Options object | ||
* @return {Promise} A Promise that gets fulfilled with the result of the request | ||
* or rejected with the error from the above topics | ||
*/ | ||
Mediator.prototype.request = function (topic, parameters, options) { | ||
if (options === void 0) { options = {}; } | ||
var self = this; | ||
var topics = { | ||
done: options.doneTopic || 'done:' + topic, | ||
error: options.errorTopic || 'error:' + topic, | ||
request: topic | ||
}; | ||
var subs = {}; | ||
var uid = null; | ||
if (_.has(options, 'uid')) { | ||
uid = options.uid; | ||
} | ||
else if (typeof parameters !== 'undefined' && parameters !== null) { | ||
if (_.has(parameters, 'id')) { | ||
uid = parameters.id; | ||
} | ||
else { | ||
uid = parameters instanceof Array ? parameters[0] : parameters.toString(); | ||
} | ||
} | ||
if (uid !== null) { | ||
topics.done += ':' + uid; | ||
topics.error += ':' + uid; | ||
} | ||
if (!options.timeout) { | ||
options.timeout = 2000; | ||
} | ||
function unsubscribe() { | ||
self.remove(topics.done, subs.done.id); | ||
self.remove(topics.error, subs.error.id); | ||
} | ||
var args = [topics.request]; | ||
if (parameters instanceof Array) { | ||
Array.prototype.push.apply(args, parameters); | ||
} | ||
else { | ||
args.push(parameters); | ||
} | ||
self.publish.apply(mediator, args); | ||
return new Promise(function (resolve, reject) { | ||
subs.done = self.once(topics.done, resolve); | ||
subs.error = mediator.once(topics.error, reject); | ||
}) | ||
.timeout(options.timeout, new Error('Mediator request timeout for topic ' + topic)) | ||
.tap(unsubscribe) | ||
.catch(function (e) { | ||
unsubscribe(); | ||
// still forward the rejection to clients | ||
throw e; | ||
}); | ||
}; | ||
; | ||
return Mediator; | ||
}(Base)); | ||
exports.Mediator = Mediator; | ||
var mediator = new Mediator(); | ||
mediator.Mediator = Mediator; | ||
module.exports = mediator; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = mediator; | ||
//# sourceMappingURL=mediator.js.map |
@@ -1,161 +0,161 @@ | ||
const Promise = require('bluebird'); | ||
const _ = require('lodash'); | ||
function Topics(mediator) { | ||
this.mediator = mediator; | ||
this.subscriptions = {}; | ||
} | ||
/** | ||
* Sets the prefix configuration for this instance, which will be part of the name | ||
* of the handled topics. | ||
* @param {String} prefix | ||
* @return {Topics} returns self for chaining | ||
*/ | ||
Topics.prototype.prefix = function(prefix) { | ||
this.prefix = prefix; | ||
return this; | ||
}; | ||
/** | ||
* Sets the entity configuration for this instance, which will be part of the name | ||
* of the handled topics. | ||
* This property is present as a convenience so it can be accessed by handlers via `this.entity` | ||
* | ||
* @param {String} entity | ||
* @return {Topics} returns self for chaining | ||
*/ | ||
Topics.prototype.entity = function(entity) { | ||
this.entity = entity; | ||
return this; | ||
}; | ||
/** | ||
* Internal function to add a subscription to the internal collection | ||
* @param {string} topic topic id | ||
* @param {Function} fn handler for the topic | ||
*/ | ||
Topics.prototype.addSubscription = function(topic, fn) { | ||
this.subscriptions[topic] = this.mediator.subscribe(topic, fn); | ||
}; | ||
/** | ||
* Builds a topic name out of the configured {@link prefix} and {@link entity} | ||
* @param {String} topicName The name of the sub-topic to build | ||
* @param {String} prefix An optional prefix to the final topic, i.e. 'done' | ||
* @return {String} The complete topic name, | ||
* i.e. {prefix}:{this.prefix}:{this.entity}:{topicName} | ||
*/ | ||
Topics.prototype.getTopic = function(topicName, prefix) { | ||
// create, done => done:wfm:user:create | ||
var parts = _.compact([this.prefix, this.entity, topicName]); | ||
if (prefix) { | ||
parts.unshift(prefix); | ||
} | ||
return parts.join(':'); | ||
}; | ||
/** | ||
* Internal function to wrap a `on` handler in a promise that will publish to the | ||
* related 'done:' and 'error:' topics | ||
* @param {Topics} self The instance, receive as a param to avoid exposing this function | ||
* in the prototype | ||
* @param {String} method The base topic to publish results to | ||
* @param {Function} fn Handler to wrap, can return a value or a Promise, will be invoked bound to self | ||
* @return {Function} Wrapped handler | ||
*/ | ||
function wrapInMediatorPromise(self, method, fn) { | ||
function publishDone(result) { | ||
if (_.isUndefined(result)) { | ||
return; | ||
"use strict"; | ||
var Promise = require("bluebird"); | ||
var _ = require("lodash"); | ||
var Topics = (function () { | ||
function Topics(mediator) { | ||
this.mediator = mediator; | ||
this.subscriptions = {}; | ||
} | ||
var topic = self.getTopic(method, 'done'); | ||
if (_.has(result, 'id')) { | ||
topic = [topic, result.id].join(':'); | ||
} else if (typeof result === 'string') { | ||
topic = [topic, result].join(':'); | ||
} | ||
self.mediator.publish(topic, result); | ||
return result | ||
} | ||
function publishError(error) { | ||
var topic = self.getTopic(method, 'error'); | ||
if (_.has(error, 'id')) { | ||
topic = [topic, error.id].join(':'); | ||
} | ||
self.mediator.publish(topic, error); | ||
} | ||
return function() { | ||
return Promise.resolve(fn.apply(self, arguments)) | ||
.then(publishDone) | ||
.catch(publishError); | ||
}; | ||
} | ||
/** | ||
* Setup a handler for a namespaced topic, if this handler returns a value or throws an Error, | ||
* it will get published to 'done' and 'error'-predixed topics as per convention. | ||
* | ||
* @param {String} method Topic name inside the namespace | ||
* @param {Function} fn Handler that can optionally return a value or a Promise | ||
* that will be treated as the result of a `request` | ||
* @return {Topics} Returns self for chaining | ||
*/ | ||
Topics.prototype.on = function(method, fn) { | ||
var topic = this.getTopic(method); | ||
this.addSubscription(topic, wrapInMediatorPromise(this, method, fn)); | ||
return this; | ||
}; | ||
/** | ||
* Setup a handler for a namespaced topic, with the 'done:' prefix | ||
* @param {String} method Topic name inside the namespace | ||
* @param {Function} fn Handler function for the topic | ||
* @return {Topics} Returns self for chaining | ||
*/ | ||
Topics.prototype.onDone = function(method, fn) { | ||
var topic = this.getTopic(method, 'done'); | ||
this.addSubscription(topic, fn.bind(this)); | ||
return this; | ||
}; | ||
/** | ||
* Setup a handler for a namespaced topic, with the 'done:' prefix | ||
* @param {String} method Topic name inside the namespace | ||
* @param {Function} fn Handler function for the topic | ||
* @return {Topics} Returns self for chaining | ||
*/ | ||
Topics.prototype.onError = function(method, fn) { | ||
var topic = this.getTopic(method, 'error'); | ||
this.addSubscription(topic, fn.bind(this)); | ||
return this; | ||
}; | ||
/** | ||
* Modifies mediator to unsubscribe to all topics configured through this instance | ||
*/ | ||
Topics.prototype.unsubscribeAll = function() { | ||
var subId; | ||
for (var topic in this.subscriptions) { | ||
if (this.subscriptions.hasOwnProperty(topic)) { | ||
subId = this.subscriptions[topic].id; | ||
this.mediator.remove(topic, subId); | ||
} | ||
} | ||
}; | ||
/** | ||
* Does a {@link Mediator.request} in the context of the namespaced topics | ||
* @param {String} topic Base topic inside the configured namespace | ||
* @param {Any} params Data for the `request` | ||
* @param {Object} options Options for the `request` | ||
* @return {Promise} The result of the `request` | ||
*/ | ||
Topics.prototype.request = function(topic, params, options) { | ||
return this.mediator.request(this.getTopic(topic), params, options); | ||
}; | ||
module.exports = Topics; | ||
/** | ||
* Sets the prefix configuration for this instance, which will be part of the name | ||
* of the handled topics. | ||
* @param {String} prefix | ||
* @return {Topics} returns self for chaining | ||
*/ | ||
Topics.prototype.withPrefix = function (prefix) { | ||
this.prefix = prefix; | ||
return this; | ||
}; | ||
; | ||
/** | ||
* Sets the entity configuration for this instance, which will be part of the name | ||
* of the handled topics. | ||
* This property is present as a convenience so it can be accessed by handlers via `this.entity` | ||
* | ||
* @param {String} entity | ||
* @return {Topics} returns self for chaining | ||
*/ | ||
Topics.prototype.withEntity = function (entity) { | ||
this.entity = entity; | ||
return this; | ||
}; | ||
; | ||
/** | ||
* Internal function to add a subscription to the internal collection | ||
* @param {string} topic topic id | ||
* @param {Function} fn handler for the topic | ||
*/ | ||
Topics.prototype.addSubscription = function (topic, fn) { | ||
this.subscriptions[topic] = this.mediator.subscribe(topic, fn); | ||
}; | ||
; | ||
/** | ||
* Builds a topic name out of the configured {@link prefix} and {@link entity} | ||
* @param {String} topicName The name of the sub-topic to build | ||
* @param {String} prefix An optional prefix to the final topic, i.e. 'done' | ||
* @return {String} The complete topic name, | ||
* i.e. {prefix}:{this.prefix}:{this.entity}:{topicName} | ||
*/ | ||
Topics.prototype.getTopic = function (topicName, prefix) { | ||
// create, done => done:wfm:user:create | ||
var parts = _.compact([this.prefix, this.entity, topicName]); | ||
if (prefix) { | ||
parts.unshift(prefix); | ||
} | ||
return parts.join(':'); | ||
}; | ||
; | ||
/** | ||
* Setup a handler for a namespaced topic, if this handler returns a value or throws an Error, | ||
* it will get published to 'done' and 'error'-predixed topics as per convention. | ||
* | ||
* @param {String} method Topic name inside the namespace | ||
* @param {Function} fn Handler that can optionally return a value or a Promise | ||
* that will be treated as the result of a `request` | ||
* @return {Topics} Returns self for chaining | ||
*/ | ||
Topics.prototype.on = function (method, fn) { | ||
var topic = this.getTopic(method); | ||
this.addSubscription(topic, this.wrapInMediatorPromise(method, fn)); | ||
return this; | ||
}; | ||
; | ||
/** | ||
* Setup a handler for a namespaced topic, with the 'done:' prefix | ||
* @param {String} method Topic name inside the namespace | ||
* @param {Function} fn Handler function for the topic | ||
* @return {Topics} Returns self for chaining | ||
*/ | ||
Topics.prototype.onDone = function (method, fn) { | ||
var topic = this.getTopic(method, 'done'); | ||
this.addSubscription(topic, fn.bind(this)); | ||
return this; | ||
}; | ||
; | ||
/** | ||
* Setup a handler for a namespaced topic, with the 'done:' prefix | ||
* @param {String} method Topic name inside the namespace | ||
* @param {Function} fn Handler function for the topic | ||
* @return {Topics} Returns self for chaining | ||
*/ | ||
Topics.prototype.onError = function (method, fn) { | ||
var topic = this.getTopic(method, 'error'); | ||
this.addSubscription(topic, fn.bind(this)); | ||
return this; | ||
}; | ||
; | ||
/** | ||
* Modifies mediator to unsubscribe to all topics configured through this instance | ||
*/ | ||
Topics.prototype.unsubscribeAll = function () { | ||
var subId; | ||
for (var topic in this.subscriptions) { | ||
if (this.subscriptions.hasOwnProperty(topic)) { | ||
subId = this.subscriptions[topic].id; | ||
this.mediator.remove(topic, subId); | ||
} | ||
} | ||
}; | ||
; | ||
/** | ||
* Does a {@link Mediator.request} in the context of the namespaced topics | ||
* @param {String} topic Base topic inside the configured namespace | ||
* @param {Any} params Data for the `request` | ||
* @param {Object} options Options for the `request` | ||
* @return {Promise} The result of the `request` | ||
*/ | ||
Topics.prototype.request = function (topic, params, options) { | ||
return this.mediator.request(this.getTopic(topic), params, options); | ||
}; | ||
; | ||
/** | ||
* Internal function to wrap a `on` handler in a promise that will publish to the | ||
* related 'done:' and 'error:' topics | ||
* @param {String} method The base topic to publish results to | ||
* @param {Function} fn Handler to wrap, can return a value or a Promise, will be invoked bound to self | ||
* @return {Function} Wrapped handler | ||
*/ | ||
Topics.prototype.wrapInMediatorPromise = function (method, fn) { | ||
var self = this; | ||
function publishDone(result) { | ||
if (_.isUndefined(result)) { | ||
return; | ||
} | ||
var topic = self.getTopic(method, 'done'); | ||
if (_.has(result, 'id')) { | ||
topic = [topic, result.id].join(':'); | ||
} | ||
else if (typeof result === 'string') { | ||
topic = [topic, result].join(':'); | ||
} | ||
self.mediator.publish(topic, result); | ||
return result; | ||
} | ||
function publishError(error) { | ||
var topic = self.getTopic(method, 'error'); | ||
if (_.has(error, 'id')) { | ||
topic = [topic, error.id].join(':'); | ||
} | ||
self.mediator.publish(topic, error); | ||
} | ||
return function () { | ||
return Promise.resolve(fn.apply(self, arguments)) | ||
.then(publishDone) | ||
.catch(publishError); | ||
}; | ||
}; | ||
return Topics; | ||
}()); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = Topics; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "fh-wfm-mediator", | ||
"version": "0.1.0-rc3", | ||
"version": "0.2.0-rc1", | ||
"description": "An implementation of the mediator pattern for use with WFM", | ||
@@ -9,4 +9,10 @@ "main": "lib/angular/mediator-ng.js", | ||
"test": "grunt", | ||
"vuln": "nsp check" | ||
"vuln": "nsp check", | ||
"prepublish": "tsc" | ||
}, | ||
"files": [ | ||
"lib/angular/mediator-ng.js", | ||
"lib/mediator.js", | ||
"lib/topics/index.js" | ||
], | ||
"keywords": [ | ||
@@ -19,7 +25,13 @@ "wfm", | ||
"dependencies": { | ||
"bluebird": "^3.4.7", | ||
"lodash": "^4.7.0", | ||
"mediator-js": "^0.9.9", | ||
"bluebird": "^3.4.7" | ||
"mediator-js": "^0.9.9" | ||
}, | ||
"devDependencies": { | ||
"@types/angular": "^1.6.3", | ||
"@types/bluebird": "^3.0.37", | ||
"@types/chai": "^3.4.34", | ||
"@types/lodash": "^4.14.52", | ||
"@types/mocha": "^2.2.38", | ||
"@types/sinon": "^1.16.34", | ||
"chai": "^3.5.0", | ||
@@ -29,7 +41,11 @@ "grunt": "^1.0.1", | ||
"grunt-mocha-test": "^0.13.2", | ||
"grunt-tslint": "^4.0.0", | ||
"load-grunt-tasks": "^3.5.2", | ||
"mocha": "^3.2.0", | ||
"nsp": "^2.6.2", | ||
"sinon": "^1.17.7" | ||
"sinon": "^1.17.7", | ||
"ts-node": "^2.0.0", | ||
"tslint": "^4.4.2", | ||
"typescript": "2.1.5" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
17279
18
6
296