New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

barracks

Package Overview
Dependencies
Maintainers
1
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

barracks - npm Package Compare versions

Comparing version 5.0.4 to 6.0.0

199

index.js

@@ -1,145 +0,100 @@

const debug = require('debug')('barracks')
const assert = require('assertf')
// const debug = require('debug')('barracks')
const series = require('run-series')
const assert = require('assert')
module.exports = Dispatcher
module.exports = dispatcher
// initialize the dispatcher with actions
// obj -> fn
function Dispatcher (actions) {
if (!(this instanceof Dispatcher)) return new Dispatcher(actions)
// initialize a new barracks instance
// null -> obj
function dispatcher () {
const actions = {}
assert(actions, "an 'actions' object should be passed as an argument")
assert.equal(typeof actions, 'object', 'actions should be an object')
_assertActionsObject(actions)
emit._actions = actions
emit.emit = emit
emit.on = on
return emit
this.locals = {}
this.payload = null
// register a new action
// (str, fn) -> obj
function on (action, cb) {
assert.equal(typeof action, 'string')
assert.equal(typeof cb, 'function')
this._current = []
this._isPending = {}
this._isHandled = {}
this._actions = actions
this._isDispatching = false
actions[action] = actions[action] ? actions[action] : []
actions[action].push(cb)
return this.dispatch.bind(this)
}
return emit
}
// dispatch event to stores
// str, obj|[obj] -> fn
Dispatcher.prototype.dispatch = function (action, payload) {
assert.equal(typeof action, 'string', "action '%s' should be a string", action)
assert(!this._isDispatching, "cannot dispatch '%s' in the middle of a dispatch", action)
// call an action and
// execute the corresponding callback
// (str, obj?) -> prom
function emit (action, data) {
assert.ok(Array.isArray(actions[action]), 'action exists')
const fn = actions[action][0]
const stack = [action]
this._current.push(action)
this._isDispatching = true
return fn(data, wait)
this._isPending = {}
this._isPending[action] = true
// internal 'wait()' function
// ([str], fn) -> prom
function wait (action, cb) {
action = Array.isArray(action) ? action : [action]
cb = cb || function () {}
this._isHandled = {}
this._isHandled[action] = false
// retrieve actions
const arr = action.map(function (name) {
const actExists = Array.isArray(actions[name])
assert.ok(actExists, 'action ' + name + ' does not exist')
const fn = actions[name][0]
return createDone(name, fn)
})
this.locals = {}
this.payload = payload
return series(arr, cb)
try {
var fn = _getAction.call(this, action)
} catch (e) {
_stopDispatching.call(this)
throw e
}
// wrap an action with a `done()` method
// for usage in `series()`
// (str, fn(any, (str, fn)) -> fn
function createDone (name, fn) {
return function (done) {
const index = stack.indexOf(name)
if (index !== -1) return emitErr('circular dependency detected')
stack.push(name)
debug("dispatch '%s'", action)
fn.call(this, _stopDispatching.bind(this))
}
if (fn.length === 2) return fn(data, retFn)
fn(data)
end()
// expose a delegation method to the registered
// actions. Calls `run-series()` under the hood
// str|[str], fn -> null
Dispatcher.prototype.waitFor = function (actions, done) {
done = done || function () {}
assert.equal(typeof done, 'function', 'callback should be a function')
// execute `wait()` and `done()`
// to both delegate new `series()` calls
// handle cb's, and exit once done
// (str, fn) -> null
function retFn (action, cb) {
if (action) return wait(action, endWrap)
endWrap()
actions = Array.isArray(actions) ? actions : [actions]
const ctx = this
function endWrap () {
if (cb) cb()
end()
}
}
const arr = actions.map(function (action) {
const fn = _getAction.call(ctx, action)
const nwFn = _thunkify.call(ctx, fn, action)
return nwFn.bind(ctx)
})
const nwArr = arr.concat(done.bind(this))
series(nwArr)
}
// deep assert the actions object
// obj -> null
function _assertActionsObject (actions) {
Object.keys(actions).forEach(function (key) {
const action = actions[key]
if (typeof action === 'object') return _assertActionsObject(action)
assert.equal(typeof action, 'function', 'action should be a function')
})
}
// wrap function to set
// `this._isHandled[action]` on end
// fn, fn -> fn
function _thunkify (fn, action) {
return function (done) {
try {
assert.equal(typeof action, 'string', '.waitFor(): requires a string or array of strings')
if (this._isPending[action]) {
assert(this._isHandled[action], "circular dependency detected while waiting for '%s'", action)
// pop name from stack
// and exit series call
// null -> null
function end () {
stack.pop()
done()
}
}
}
} catch(e) {
_stopDispatching.call(this)
throw e
}
this._isPending[action] = true
this._isHandled[action] = false
function fin () {
this._current.pop()
this._isHandled[action] = true
done()
// emit an error
// any -> null
function emitErr (err) {
const emitter = actions.error ? actions.error[0] : function () {}
emitter(err)
}
this._current.push(action)
debug("'%s' -> '%s'", this._current[this._current.length - 2], action)
fn(fin.bind(this))
}
}
// get the dispatched action recursively
// [str], str -> fn
function _getAction (action, arr, index) {
arr = arr || action.split('_')
index = index || 0
const val = arr[index]
if (typeof val === 'object') return _getAction.call(this, action, arr, index++)
var fn = this._actions
arr.forEach(function (obj, i) {
assert(fn[arr[i]], "action '%s' is not registered", action)
fn = fn[arr[i]]
})
assert.equal(typeof fn, 'function', "action '%s' is not registered", action)
return fn.bind(this)
}
// reset internal state
// null -> null
function _stopDispatching () {
this._isDispatching = false
this._isPending = {}
this._isHandled = {}
this.payload = null
this._current = []
this.locals = {}
}
{
"name": "barracks",
"version": "5.0.4",
"description": "An event dispatcher for the flux architecture",
"version": "6.0.0",
"description": "Action dispatcher for unidirectional data flows",
"main": "index.js",
"scripts": {
"lint": "eslint .",
"test": "NODE_ENV=test node test | colortape",
"test-cov": "NODE_ENV=test istanbul cover test.js"
"test": "standard && NODE_ENV=test node test",
"test-cov": "standard && NODE_ENV=test istanbul cover test.js",
"watch": "watch 'npm t'"
},

@@ -15,2 +15,6 @@ "repository": "yoshuawuyts/barracks",

"flux",
"action",
"minimal",
"emitter",
"event",
"react",

@@ -21,11 +25,9 @@ "react-component"

"devDependencies": {
"colortape": "^0.1.1",
"coveralls": "~2.10.0",
"eslint": "^0.11.0",
"istanbul": "~0.2.10",
"make-lint": "^1.0.1",
"tape": "^3.0.3"
"standard": "^4.5.4",
"tape": "^3.0.3",
"watch": "^0.16.0"
},
"dependencies": {
"assertf": "^1.0.0",
"debug": "^2.0.0",

@@ -35,3 +37,3 @@ "run-series": "^1.1.2"

"files": [
"HISTORY.md",
"README.md",
"LICENSE",

@@ -38,0 +40,0 @@ "index.js"

@@ -7,163 +7,87 @@ # barracks

Event dispatcher for the [flux architecture][flux]. Provides event composition
through `this.waitFor()` and checks for circular dependencies with a small
interface of only 3 functions.
Action dispatcher for unidirectional data flows. Provides action composition
and checks for circular dependencies with a small interface of only 3
functions.
```
╔═════╗ ╔════════════╗ ╔════════╗ ╔═════════════════╗
║ API ║<──────>║ Middleware ║──────>║ Stores ║──────>║ View Components ║
╚═════╝ ╚════════════╝ ╚════════╝ ╚═════════════════╝
^ │
│ │
╔════════════╗ │
║ Dispatcher ║ │
╚════════════╝ │
^ │
└────────────────────────────────────────┘
```
## Installation
```sh
npm install barracks
$ npm install barracks
```
## Overview
## Usage
````js
var barracks = require('barracks');
const barracks = require('barracks')
// Initialize dispatcher.
const dispatcher = barracks()
const store = []
var dispatcher = barracks({
users: {
add: function(next) {
console.log(user + ' got added');
next();
}
},
courses: {
get: function(next) {
console.log('Get ' + this.payload);
next();
},
set: function(next) {
console.log('Set ' + this.payload);
next();
}
}
});
dispatcher.on('error', err => console.log(err))
dispatcher.on('insert', data => store.push(data.name))
dispatcher.on('upsert', (data, wait) => {
const index = store.indexOf(data.prevName)
if (index !== -1) return wait('insert')
store[index] = data.newName
})
// Dispatch an event.
dispatcher('users_add', 'Loki');
// => 'Loki got added'
dispatcher('insert', {name: 'Loki'})
dispatcher('upsert', {name: 'Loki', newName: 'Tobi'})
````
## API
#### dispatcher = barracks(actions)
Initialize a new `barracks` instance. Returns a function.
```js
// Initialize without namespaces.
### dispatcher = barracks()
Initialize a new `barracks` instance.
var dispatcher = barracks({
user: function() {},
group: function() {}
});
### dispatcher.on(action, cb(data, wait))
Register a new action. Checks for circular dependencies when dispatching. The
callback receives the passed in data and a `wait(actions[, cb])` function that
can be used to call other actions internally. `wait()` accepts a single action
or an array of actions and an optional callback as the final argument.
// Initialize with namespaces.
### dispatcher(event[, data])
Call an action and execute the corresponding callback. Alias:
`dispatcher.emit(event[, data])`.
var dispatcher = barracks({
users: {
add: function() {},
remove: function() {}
},
courses: {
get: function() {},
put: function() {}
}
});
```
## Events
### .on('error', cb(err))
Handle errors. Warns if circular dependencies exists.
#### dispatcher(action, data)
`barracks()` returns a dispatcher function which can be called to dispatch an
action. By dispatching an action you call the corresponding function from
the dispatcher and pass it data. You can think of it as just calling a
function.
## FAQ
### What is an "action dispatcher"?
An action dispatcher gets data from one place to another without tightly
coupling the code. The best known use case for this is in the `flux` pattern.
Say you want to update a piece of data (for example a user's name), instead of
directly calling the update logic inside the view the action calls a function
that updates the user's name for you. Now all the views that need to update a
user's name can call the same action and pass in the relevant data. This
pattern tends to make views more robust and easier to maintain.
In order to access namespaced functions you can delimit your string with
underscores. So to access `courses.get` you'd dispatch the string `courses_get`.
````js
// Call a non-namespaced action.
dispatcher('group', [123, 'hello']);
### Why did you build this?
Passing messages around should not be complicated. Many `flux` implementations
casually throw around framework specific terminology making new users feel
silly for not following along. I don't like that. `barracks` is a package that
takes node's familiar `EventEmitter` interface and adapts it for use as an
action dispatcher.
// Call a namespaced action.
dispatcher('users_add', {foo: 'bar'});
````
### I want to start using barracks, but I'm not sure how to use it
That's fine, that means this readme needs to be improved. Would you mind
opening an [issue](https://github.com/yoshuawuyts/barracks/issues) and explain
what you don't understand? I want `barracks` to be comprehensive for
developers of any skill level, so don't hesitate to ask questions if you're
unsure about something.
#### ctx.waitFor(action)
Execute another function within the dispatcher before proceeding. Registered
callbacks are always bound to the scope of the dispatcher, so you can just
call `this.waitFor` to access the function from within a registered callback.
```js
var dispatcher = barracks({
init: function(next) {
console.log('1');
this.waitFor(['add', 'listen'], function() {
console.log('4');
next();
});
},
add: function(next) {
setTimeout(function() {
console.log('2');
done();
}, 10);
},
listen: function(next) {
console.log('3');
next();
}
});
### Why didn't you include feature X?
An action dispatcher doesn't a lot of features to pass a message from A to B.
`barracks` was built for flexibility. If you feel you're repeating yourself a
lot with `barracks` or are missing a feature, feel free to wrap and extend it
however you like.
dispatcher('init');
// => 1 2 3
```
### What data store do you recommend using with barracks?
In flux it's common to store your application state in a data store.I think a
data store should be immutable, single-instance and allow data access through
cursors / lenses. At the moment of writing I haven't found a data store I'm
pleased with, so I'll probably end up writing one in the near future.
#### ctx.payload
`this.payload` contains the data provided by `dispatcher()`.
```js
var dispatcher = barracks({
init: function(next) {
console.log(this.payload);
}
});
## See Also
- [wayfarer](https://github.com/yoshuawuyts/wayfarer) - composable trie based route
dispatcher('init', 'fooBar');
// => 'fooBar'
```
#### ctx.locals=
`this.locals` is shared between all (delegated) function calls and acts as the
location to share data between function calls. For example when you retrieve
a token from a store and want to make it available to all subsequent functions.
The payload provided by `dispatcher()` is available under `this.locals.payload`.
```js
var dispatcher = barracks({
add: function(next) {
this.locals.token = 'asdf12345';
next();
});
},
fetch: function(next) {
this.waitFor(['add'], function() {
console.log(this.locals.token);
next();
});
}
});
dispatcher('fetch');
// => 'asdf12345'
```
## License

@@ -170,0 +94,0 @@ [MIT](https://tldrlegal.com/license/mit-license)

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