Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Action dispatcher for unidirectional data flows. Creates tiny models of data that can be accessed through actions with an API of only 5 functions
const barracks = require('barracks')
const store = barracks({
onError: (err, state, createSend) => {
console.error(`error: ${err}`)
}),
onAction: (data, state, name, caller, createSend) => {
console.log(`data: ${data}`)
})
onStateChange: (data, state, prev, caller, createSend) => {
console.log(`state: ${prev} -> ${state}`)
})
})
store.model({
namespace: 'cakes',
state: {},
effects: {},
reducers: {},
subscriptions: {}
})
const createSend = store.start({ noSubscriptions: true })
const send = createSend('myDispatcher', true)
document.addEventListener('DOMContentLoaded', () => {
store.start() // fire up subscriptions
const state = store.state()
send('foo:start', { name: 'Loki' })
})
Initialize a new barracks
instance. Takes an optional object of handlers.
Handlers can be:
effect
or
subscription
emit an error. If no handler is passed, the default handler
will throw
on each error.action
is fired.state
.createSend()
is a special function that allows the creation of a new named
send()
function. The first argument should be a string which is the name, the
second argument is a boolean callOnError
which can be set to true
to call
the onError
hook istead of a provided callback. It then returns a
send(actionName, data?)
function.
Handlers should be used with care, as they're the most powerful interface into
the state. For application level code it's generally recommended to delegate to
actions inside models using the send()
call, and only shape the actions
inside the handlers.
Register a new model on the store. Models are optionally namespaced objects
with an initial state
, and handlers for dealing with data:
state
inside the modelactions
actions
, can call actions
actions
state
within handlers is immutable through Object.freeze()
and thus cannot
be modified. Return data from reducers
to modify state
. See handler
signatures for more info on the handlers.
For debugging purposes internal references to values can be inspected through a series of private accessors:
store._subscriptions
store._reducers
store._effects
store._models
Get the current state from the store. Opts can take the following values:
Object.freeze()
. Useful for optimizing performance in production
builds.Start the store and get a createSend(name)
function. Pass a unique name
to
createSend()
to get a send()
function. Opts can take the following values:
subscriptions
when starting the application. Useful to delay init
functions until the DOM has loaded.false
to not register effects
when
starting the application. Useful when only wanting the initial state
reducers
when
starting the application. Useful when only wanting the initial state
If the store has disabled any of the handlers (e.g. { reducers: false }
),
calling store.start()
a second time will register the remaining values. This
is a useful if not everything can be started at the same time (e.g. have
subscriptions
wait for the DOMContentLoaded
event).
Send a new action to the models with optional data attached. Namespaced models
can be accessed by prefixing the name with the namespace separated with a :
,
e.g. namespace:name
.
These are the signatures for the properties that can be passed into a model.
An optional string that causes state
, effects
and reducers
to be
prefixed.
app.model({
namespace: 'users'
})
State can either be a value or an object of values that is used as the initial
state for the application. If namespaced the values will live under
state[namespace]
.
app.model({
namespace: 'hey',
state: { foo: 'bar' }
})
app.model({
namespace: 'there',
state: { bin: [ 'beep', 'boop' ] }
})
app.model({
namespace: 'people',
state: 'oi'
}})
Reducers are synchronous functions that return a value syncrhonously. No
eventual values, just values that are relevant for the state. It takes two
arguments of data
and state
. data
is the data that was emitted, and
state
is the current state. Each action has a name that can be accessed
through send(name)
, and when under a namespace can be accessed as
send(namespace:name)
. When operating under a namespace, reducers only have
access to the state within the namespace.
// some model
app.model({
namespace: 'plantcake',
state: {
enums: [ 'veggie', 'potato', 'lettuce' ]
paddie: 'veggie'
}
})
// so this model can't access anything in the 'plantcake' namespace
app.model({
namespace: 'burlybeardos',
state: { count: 1 },
reducers: {
feedPlantcake: (data, state) => {
return { count: state.count + 1 }
},
trimBeard: (data, state) => ({ count: state.count - 1 })
}
})
effects
are asynchronous methods that can be triggered by actions
in
send()
. They never update the state directly, but can instead do thing
asyncrhonously, and then call send()
again to trigger a reducer
that can
update the state. effects
can also trigger other effects
, making them fully
composable. Generalyy it's recommended to only have effects
without a
namespace
call other effects
, as to keep namespaced models as isolated as
possible.
When an effect
is done executing, or encounters an error, it should call the
final done(err)
callback. If the effect
was called by another effect
it
will call the callback of the caller. When an error propegates all the way to
the top, the onError
handler will be called, registered in
barracks(handlers)
. If no callback is registered, errors will throw
.
Having callbacks in effects
means that error handling can be formalized
without knowledge of the rest of the application leaking into the model. This
also causes effects
to become fully composable, which smooths parallel
development in large teams, and keeps the mental overhead low when developing a
single model.
const http = require('xhr')
const app = barracks({
onError: (data, state, prev, send) => send('app:error', data)
})
app.model({
namespace: 'app',
effects: {
error: (data, state, send, done) => {
// if doing http calls here be super sure not to get lost
// in a recursive error handling loop: remember this IS
// the error handler
console.error(data.message)
done()
}
}
})
app.model({
namespace: 'foo',
state: { foo: 1 },
reducers: {
moreFoo: (data, state) => ({ foo: state.foo + data.count })
}
effects: {
fetch: (data, state, send, done) => {
http('foobar.com', function (err, res, body) {
if (err || res.statusCode !== 200) {
return done(new Error({
message: 'error accessing server',
error: err
}))
} else {
send('moreFoo', { count: foo.count }, done)
}
})
}
}
})
subscriptions
are read-only sources of data. This means they cannot be
triggered by actions, but can emit actions themselves whenever they want. This
is useful for stuff like listening to keyboard events or incoming websocket
data. They should generally be started when the application is loaded, using
the DOMContentLoaded
listener.
app.model({
subscriptions: {
emitWoofs: (send, done) => {
// emit a woof every second
setInterval(() => send('printWoofs', { woof: 'meow?' }, done), 1000)
}
},
effects: {
printWoofs: (data, state) => console.log(data.woof)
}
})
done()
is passed as the final argument so if an error occurs in a subscriber,
it can be communicated to the onError
hook.
An action dispatcher gets data from one place to another without tightly
coupling 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.
Passing messages around should not be complicated. Many flux
implementations
casually throw restrictions at users without having a clear architecture. I
don't like that. barracks
is a package creates a clear flow of data within an
application, concerning itself with state, code separation, and data flow. I
believe that having strong opinions and being transparant in them makes for
architectures than sprinkles of opinions left and right, without a cohesive
story as to why.
choo
is a framework that handles views, data and all problems related to
that. This is a package that only concerns itself with data flow, without being
explicitely tied to the DOM.
Welllll, no. It's technically five functions with a high arity, hah. Nah,
you're right - but five functions sounds good. Besides: you don't need to
know all options and toggles to get this working; that only relevant once you
start hitting edge cases like we did in choo
:sparkles:
$ npm install barracks
FAQs
Action dispatcher for unidirectional data flows
The npm package barracks receives a total of 20 weekly downloads. As such, barracks popularity was classified as not popular.
We found that barracks demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.