Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fh-wfm-mediator

Package Overview
Dependencies
Maintainers
5
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fh-wfm-mediator - npm Package Compare versions

Comparing version 0.4.0-rc1 to 1.0.0-pre.1

.eslintrc

45

lib/angular/mediator-ng.js

@@ -1,22 +0,27 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var angular = require("angular");
var mediator = require("../mediator");
'use strict';
var mediator = require('../mediator');
angular.module('wfm.core.mediator', ['ng'])
.factory('mediator', function mediatorService($q) {
var originalRequest = mediator.request;
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 subscriber;
};
return mediator;
.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;
});
exports.default = 'wfm.core.mediator';
//# sourceMappingURL=mediator-ng.js.map
module.exports = 'wfm.core.mediator';

@@ -1,5 +0,437 @@

"use strict";
var mediator_1 = require("./mediator");
var mediator = new mediator_1.default();
var _ = require('lodash');
var Promise = require('bluebird');
const CONSTANTS = require('../constants');
//Based on https://github.com/ajacksified/Mediator.js
//This change is based on an assumption that the subscribes respond with a promise.
// We'll generate guids for class instances for easy referencing later on.
// Subscriber instances will have an id that can be refernced for quick
// lookups.
function guidGenerator() {
var S4 = function() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
// Subscribers are instances of Mediator Channel registrations. We generate
// an object instance so that it can be updated later on without having to
// unregister and re-register. Subscribers are constructed with a function
// to be called, options object, and context.
function Subscriber(fn, options, context) {
if (!(this instanceof Subscriber)) {
return new Subscriber(fn, options, context);
}
this.id = guidGenerator();
this.fn = fn;
this.options = options;
this.context = context;
this.channel = null;
}
// Mediator.update on a subscriber instance can update its function,context,
// or options object. It takes in an object and looks for fn, context, or
// options keys.
Subscriber.prototype.update = function(options) {
if (options) {
this.fn = options.fn || this.fn;
this.context = options.context || this.context;
this.options = options.options || this.options;
if (this.channel && this.options && this.options.priority !== undefined) {
this.channel.setPriority(this.id, this.options.priority);
}
}
};
function Channel(namespace, parent) {
if (!(this instanceof Channel)) {
return new Channel(namespace);
}
this.namespace = namespace || "";
this._subscribers = [];
this._channels = {};
this._parent = parent;
this.stopped = false;
}
// A Mediator channel holds a list of sub-channels and subscribers to be fired
// when Mediator.publish is called on the Mediator instance. It also contains
// some methods to manipulate its lists of data; only setPriority and
// StopPropagation are meant to be used. The other methods should be accessed
// through the Mediator instance.
Channel.prototype.addSubscriber = function(fn, options, context) {
var subscriber = new Subscriber(fn, options, context);
if (options && options.priority !== undefined) {
// Cheap hack to either parse as an int or turn it into 0. Runs faster
// in many browsers than parseInt with the benefit that it won't
// return a NaN.
options.priority = options.priority >> 0;
if (options.priority < 0) {
options.priority = 0;
}
if (options.priority >= this._subscribers.length) {
options.priority = this._subscribers.length - 1;
}
this._subscribers.splice(options.priority, 0, subscriber);
} else {
this._subscribers.push(subscriber);
}
subscriber.channel = this;
return subscriber;
};
// The channel instance is passed as an argument to the mediator subscriber,
// and further subscriber propagation can be called with
// channel.StopPropagation().
Channel.prototype.stopPropagation = function() {
this.stopped = true;
};
Channel.prototype.getSubscriber = function(identifier) {
var x = 0,
y = this._subscribers.length;
for (x, y; x < y; x++) {
if (this._subscribers[x].id === identifier || this._subscribers[x].fn === identifier) {
return this._subscribers[x];
}
}
};
// Channel.setPriority is useful in updating the order in which Subscribers
// are called, and takes an identifier (subscriber id or named function) and
// an array index. It will not search recursively through subchannels.
Channel.prototype.setPriority = function(identifier, priority) {
var oldIndex = 0,
x = 0,
sub, firstHalf, lastHalf, y;
for (x = 0, y = this._subscribers.length; x < y; x++) {
if (this._subscribers[x].id === identifier || this._subscribers[x].fn === identifier) {
break;
}
oldIndex++;
}
sub = this._subscribers[oldIndex];
firstHalf = this._subscribers.slice(0, oldIndex);
lastHalf = this._subscribers.slice(oldIndex + 1);
this._subscribers = firstHalf.concat(lastHalf);
this._subscribers.splice(priority, 0, sub);
};
Channel.prototype.addChannel = function(channel) {
this._channels[channel] = new Channel((this.namespace ? this.namespace + ':' : '') + channel, this);
};
Channel.prototype.hasChannel = function(channel) {
return this._channels.hasOwnProperty(channel);
};
Channel.prototype.returnChannel = function(channel) {
return this._channels[channel];
};
Channel.prototype.removeSubscriber = function(identifier) {
var x = this._subscribers.length - 1;
// If we don't pass in an id, we're clearing all
if (!identifier) {
this._subscribers = [];
return;
}
// Going backwards makes splicing a whole lot easier.
for (x; x >= 0; x--) {
if (this._subscribers[x].fn === identifier || this._subscribers[x].id === identifier) {
this._subscribers[x].channel = null;
this._subscribers.splice(x, 1);
}
}
};
// This will publish arbitrary arguments to a subscriber and then to parent
// channels.
Channel.prototype.publish = function(data) {
var x = 0,
y = this._subscribers.length,
shouldCall = false,
subscriber,
subsBefore, subsAfter;
var self = this;
var promises = [];
// Priority is preserved in the _subscribers index.
for (x, y; x < y; x++) {
// By default set the flag to false
shouldCall = false;
subscriber = this._subscribers[x];
if (!this.stopped) {
subsBefore = this._subscribers.length;
if (subscriber.options !== undefined && typeof subscriber.options.predicate === "function") {
if (subscriber.options.predicate.apply(subscriber.context, data)) {
// The predicate matches, the callback function should be called
shouldCall = true;
}
} else {
// There is no predicate to match, the callback should always be called
shouldCall = true;
}
}
// Check if the callback should be called
if (shouldCall) {
// Check if the subscriber has options and if this include the calls options
if (subscriber.options && subscriber.options.calls !== undefined) {
// Decrease the number of calls left by one
subscriber.options.calls--;
// Once the number of calls left reaches zero or less we need to remove the subscriber
if (subscriber.options.calls < 1) {
this.removeSubscriber(subscriber.id);
}
}
// Now we call the callback, if this in turns publishes to the same channel it will no longer
// cause the callback to be called as we just removed it as a subscriber
var subscriberResult = subscriber.fn.apply(subscriber.context, data);
//If the result of the subscriber function is a promise, we are interested in the result.
//If it isn't, we are not interested in the result.
subscriberResult = _.isObject(subscriberResult) && _.isFunction(subscriberResult.then) ? subscriberResult : Promise.resolve();
//Handling the result
subscriberResult = subscriberResult.then(function(result) {
return result === null || result === undefined ? result : {
topic: self.namespace,
result: result
};
});
promises.push(subscriberResult);
subsAfter = this._subscribers.length;
y = subsAfter;
if (subsAfter === subsBefore - 1) {
x--;
}
}
}
this.stopped = false;
if (this._parent) {
this._parent.publish(data);
}
//All related promises to this channel have been added.
return _.flatten(promises);
};
function Mediator() {
if (!(this instanceof Mediator)) {
return new Mediator();
}
this._channels = new Channel('');
}
// A Mediator instance is the interface through which events are registered
// and removed from publish channels.
// Returns a channel instance based on namespace, for example
// application:chat:message:received. If readOnly is true we
// will refrain from creating non existing channels.
Mediator.prototype.getChannel = function(namespace, readOnly) {
var channel = this._channels,
namespaceHierarchy = namespace.split(':'),
x = 0,
y = namespaceHierarchy.length;
if (namespace === '') {
return channel;
}
if (namespaceHierarchy.length > 0) {
for (x, y; x < y; x++) {
if (!channel.hasChannel(namespaceHierarchy[x])) {
if (readOnly) {
break;
} else {
channel.addChannel(namespaceHierarchy[x]);
}
}
channel = channel.returnChannel(namespaceHierarchy[x]);
}
}
return channel;
};
// Pass in a channel namespace, function to be called, options, and context
// to call the function in to Subscribe. It will create a channel if one
// does not exist. Options can include a predicate to determine if it
// should be called (based on the data published to it) and a priority
// index.
Mediator.prototype.subscribe = function(channelName, fn, options, context) {
var channel = this.getChannel(channelName || "", false);
options = options || {};
context = context || {};
return channel.addSubscriber(fn, options, context);
};
// Pass in a channel namespace, function to be called, options, and context
// to call the function in to Subscribe. It will create a channel if one
// does not exist. Options can include a predicate to determine if it
// should be called (based on the data published to it) and a priority
// index.
Mediator.prototype.once = function(channelName, fn, options, context) {
options = options || {};
options.calls = 1;
return this.subscribe(channelName, fn, options, context);
};
// Returns a subscriber for a given subscriber id / named function and
// channel namespace
Mediator.prototype.getSubscriber = function(identifier, channelName) {
var channel = this.getChannel(channelName || "", true);
// We have to check if channel within the hierarchy exists and if it is
// an exact match for the requested channel
if (channel.namespace !== channelName) {
return null;
}
return channel.getSubscriber(identifier);
};
// Remove a subscriber from a given channel namespace recursively based on
// a passed-in subscriber id or named function.
Mediator.prototype.remove = function(channelName, identifier) {
var channel = this.getChannel(channelName || "", true);
if (channel.namespace !== channelName) {
return false;
}
channel.removeSubscriber(identifier);
};
// Publishes arbitrary data to a given channel namespace. Channels are
// called recursively downwards; a post to application:chat will post to
// application:chat:receive and application:chat:derp:test:beta:bananas.
// Called using Mediator.publish("application:chat", [ args ]);
Mediator.prototype.publish = function(channelName) {
var self = this;
var channel = this.getChannel(channelName || "", true);
if (channel.namespace !== channelName) {
return null;
}
var args = Array.prototype.slice.call(arguments, 1);
args.push(channel);
//All promises must be resolved for the published topic to be complete.
return Promise.all(channel.publish(args)).then(function(results) {
//Removing any un-required results
//NOTE: The subscriber with the highest priority result is resolved.
var topicResponse = _.first(_.compact(_.flatten(results)));
return topicResponse ? topicResponse.result : undefined;
}).then(function(result) {
if (result) {
self.publish(CONSTANTS.DONE_TOPIC_PREFIX + CONSTANTS.TOPIC_SEPERATOR + channel.namespace, result);
}
return result;
});
};
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
*
* @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 {Number} [options.timeout] - Optional timeout for the request to finish
*
* @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 || {};
if (!options.timeout) {
options.timeout = 60000;
}
var args = [topic];
if (parameters instanceof Array) {
Array.prototype.push.apply(args, parameters);
} else if (parameters) {
args.push(parameters);
}
var publishPromise = self.publish.apply(mediator, args);
return publishPromise ? publishPromise.timeout(options.timeout, new Error('Mediator request timeout for topic ' + topic)) : Promise.reject(new Error("No subscribers exist for topic " + topic));
};
// Alias some common names for easy interop
Mediator.prototype.on = Mediator.prototype.subscribe;
Mediator.prototype.bind = Mediator.prototype.subscribe;
Mediator.prototype.emit = Mediator.prototype.publish;
Mediator.prototype.trigger = Mediator.prototype.publish;
Mediator.prototype.off = Mediator.prototype.remove;
// Finally, expose it all.
Mediator.Channel = Channel;
Mediator.Subscriber = Subscriber;
Mediator.version = "0.9.8";
var mediator = new Mediator();
mediator.Mediator = Mediator;
module.exports = mediator;
//# sourceMappingURL=index.js.map

@@ -1,103 +0,180 @@

"use strict";
var Promise = require("bluebird");
var _ = require("lodash");
var Topics = (function () {
function Topics(mediator) {
this.mediator = mediator;
this.subscriptions = {};
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'
* @param {String} [topicUid] An optional unique identifier to append
* @return {String} The complete topic name,
* i.e. {prefix}:{this.prefix}:{this.entity}:{topicName}:{topicUid}
*/
Topics.prototype.getTopic = function(topicName, prefix, topicUid) {
// create, done => done:wfm:user:create
var parts = _.compact([this.prefix, this.entity, topicName, topicUid]);
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;
}
Topics.prototype.prefix = function (prefix) {
this._prefix = prefix;
return this;
};
;
Topics.prototype.entity = function (entity) {
this._entity = entity;
return this;
};
;
Topics.prototype.addSubscription = function (topic, fn) {
this.subscriptions[topic] = this.mediator.subscribe(topic, fn);
};
;
Topics.prototype.getTopic = function (topicName, prefix, topicUid) {
var parts = _.compact([this._prefix, this._entity, topicName, topicUid]);
if (prefix) {
parts.unshift(prefix);
}
return parts.join(':');
};
;
Topics.prototype.on = function (method, fn) {
var topic = this.getTopic(method);
this.addSubscription(topic, this.wrapInMediatorPromise(method, fn));
return this;
};
;
Topics.prototype.onDone = function (method, fn) {
var topic = this.getTopic(method, 'done');
this.addSubscription(topic, fn.bind(this));
return this;
};
;
Topics.prototype.onError = function (method, fn) {
var topic = this.getTopic(method, 'error');
this.addSubscription(topic, fn.bind(this));
return this;
};
;
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);
}
}
};
;
Topics.prototype.request = function (topic, params, options) {
return this.mediator.request(this.getTopic(topic), params, options);
};
;
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 () {
var _prefix = self._prefix, _entity = self._entity, mediator = self.mediator;
var context = {
entity: _entity,
mediator: mediator,
prefix: _prefix,
topic: self.getTopic(method)
};
return Promise.resolve(fn.apply(context, arguments))
.then(publishDone)
.catch(publishError);
};
};
return Topics;
}());
;
module.exports = Topics;
//# sourceMappingURL=index.js.map
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);
};
/**
* 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.publish = function(topic) {
var args = Array.prototype.slice.call(arguments, 1);
args.unshift(this.getTopic(topic));
return this.mediator.publish.apply(this.mediator, args);
};
module.exports = Topics;
{
"name": "fh-wfm-mediator",
"version": "0.4.0-rc1",
"version": "1.0.0-pre.1",
"description": "An implementation of the mediator pattern for use with WFM",
"main": "lib/angular/mediator-ng.js",
"types": "lib/angular/mediator-ng.d.ts",
"repository": "https://github.com/feedhenry-raincatcher/raincatcher-mediator",
"scripts": {
"test": "grunt",
"build": "grunt build",
"prepublish": "npm run build"
"test": "grunt"
},

@@ -22,26 +19,15 @@ "keywords": [

"lodash": "^4.7.0",
"mediator-js": "^0.9.9",
"@types/bluebird": "^3.0.37",
"@types/angular": "^1.6.3",
"@types/lodash": "^4.14.52"
"shortid": "^2.2.8"
},
"devDependencies": {
"@types/chai": "^3.4.34",
"@types/mocha": "^2.2.38",
"@types/node": "^7.0.5",
"@types/sinon": "^1.16.34",
"chai": "^3.5.0",
"grunt": "^1.0.1",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-eslint": "18.0.0",
"grunt-mocha-test": "^0.13.2",
"grunt-ts": "^6.0.0-beta.11",
"grunt-tslint": "^4.0.0",
"load-grunt-tasks": "^3.5.2",
"mocha": "^3.2.0",
"sinon": "^1.17.7",
"ts-node": "^2.0.0",
"tslint": "^4.4.2",
"typescript": "^2.2.1"
"sinon-as-promised": "^4.0.3",
"sinon-chai": "^2.11.0"
}
}

@@ -14,9 +14,35 @@ # FeedHenry RainCatcher mediator [![Build Status](https://travis-ci.org/feedhenry-raincatcher/raincatcher-mediator.png)](https://travis-ci.org/feedhenry-raincatcher/raincatcher-mediator)

### Subscription Callbacks
When passing a `callback` to a `mediator.subscribe` function, it is necessary to return a `Promise` if the operation is asynchronous or if the response from the subscriber is required.
```javascript
var mediator = require('fh-wfm-mediator');
var Promise = require('bluebird');
mediator.subscribe("wfm:topic", function(topicData) {
return new Promise(function(resolve, reject) {
doSomeAyncFunction(topicData, function(err, result){
err ? reject(err) : resolve(result);
});
});
});
//The published topic will not resolve until all of the asynchronous subscribers have resolved / rejected
//The `result` is the resolved value of the highest priority subscriber.
mediator.publish("wfm:topic").then(function(result) {
console.log("All of the subscribers have resolved.", result);
}).catch(function(err) {
console.error("An error occurred when executing topic wfm:topic", err);
});
```
### `Topics` utilities
This module also provides a fluent, promise-based API for subscribing to convention and adhering to the request-response pattern used throughout the RainCatcher modules and available through `mediator#request`.
Namely if a `data:read` topic that is used to provide a feature such as reading data from a remote source asyncronously, the result of the operation is by convention published in the `done:data:read` topic, and if it results in an error, it is published to the `error:data:read` topic.
This utility module helps with enforcing the same namespace for a set of related topics without repeating string literals or constants, and adhering to the convention above. It is available under [`lib/topics`](./lib/topics/index.js) with jsdoc comments.
#### Example

@@ -26,24 +52,49 @@

var mediator = require('fh-wfm-mediator');
var Topics = require('fh-wfm-mediator/lib/topics');
var Topic = require('fh-wfm-mediator/lib/topics');
var topics = new Topics(mediator)
.withPrefix('wfm')
.withEntity('user')
//A set of topics for saving user data
var userDataTopics = new Topic(mediator)
.prefix('wfm:data')
.entity('user')
.on('read', function(id) {
//asyncReadUser returns a Promise
return asyncReadUser(id);
}).on('update', function(userToUpdate) {
//asyncReadUser returns a Promise
return asyncUpdateUser(userToUpdate);
});
new Topic(mediator)
.prefix('wfm')
.entity('user')
// This will subscribe to wfm:user:read
// and publish results to done:wfm:user:read:{id}
// and errors to error:wfm:user:read:{id}
.on('read', function(id) {
// will request to 'data:user:read'
return this.mediator.request(['data', this.entity, 'read'].join(':'), id);
// will publish to 'wfm:user:data:read', which returns a Promise.
return userDataTopics.publish('read', id).then(function(user) {
//We have retrieved the user, we can apply any additional asynchronous operations we need when the resolving the user
return readUserGroupInformation(user.id).then(function(groupInformation) {
user.groupName = groupInformation.name;
return user;
});
});
})
// If you do not return a Promise from the handler function,
// you must manually publish the result to another topic so it can be consumed
.on('delete', function(id) {
var self = this;
this.mediator.request(this.entity + ':delete', id).then(function() {
self.mediator.publish('done:ui:user:deleted:' + id);
}).catch(function(e) {
self.mediator.publish('error:ui:user:deleted:' + id, e);
.on('update_location', function(id, location) {
//If we don't want to wait for the subscribers to resolve, just return null.
userDataTopics.publish('read', id).then(function(user) {
//We have retrieved the user, we can apply any additional asynchronous operations we need when the resolving the user
user.location = location;
userDataTopics.publish('update', user);
});
return null;
});
mediator.publish('wfm:user:read', "userid1234").then(function(user) {
//All of the subscribers have resolved.
console.log("User read with id " + user.id + " and group name " + user.groupName);
}).catch(function(err) {
console.log("Error reading user information", err);
});
```

@@ -77,3 +128,3 @@

...
})
}
```

@@ -87,5 +138,1 @@

```
# NPM Publishing
This module is written in TypeScript, in order to publish it to npm as compiled JavaScript files along with TypeScript typings and source maps, run `npm run build` before `npm publish`.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc