Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Bly is a tiny framework to help you write web apps using a Flux architecture. It's designed to give help you structure and organise your code in anyway that works for your app. Simple enough to work on small prototypes, elegant enough to work on bigger projects too citation needed. It's designed to empower you and then get out of your way.
Stability: experimental. So the claims above might not yet be met, be ready for bugs and be careful using it in production.
Simple app interface
new Bly.App()
app.stores
(we'll let you decide how to implement them)app.action
(again, letting you decide how to implement stores)app.render
(called every time after an action was dispatched)app.start
(from now on actions can be injected)app.inject
Plugins for code organisation
app.register
plugin, options, next
plugin.action
, plugin.stores
, etc.plugin.register
render
function using plugin.results
var app = new Bly.App();
// register store
var pageStore = yourPageStore();
app.stores('pages', pageStore);
// handle actions
app.action({
name: 'navigate',
handler: function(waitFor, payload) {
pageStore.navigate(payload);
}
});
// render your app
app.render(function() {
React.renderComponent({
App({
stores: stores
});
})
});
// start your app
app.start();
Making it easier to create great UI's and app experiences for the end user, and keeping it that way through the course of the project. That's the most important thing; if I can't imagine how something would actually benefit the end user I probably won't put it in. This doesn't mean that these benefits can sometimes be quite indirect. For example, if something just greatly simplifies the developing experience on my side, that'll make it easier for me to be creative, try different things, pay attention to details, feel happy about my project. All of which I believe in the end contribute to the quality of the final product.
Especially the keeping it that way is important, as that's where I see a lot of approaches go down the drain. If in any way possible I highly favour approaches that will make my codebase grow linearly relative to the complexity of the app. There are plenty of frameworks / architectures out there that are very clean and easy to start off with, but as soon as you step outside the bounds of it, doing anything becomes very complex. It should be relatively easily to get started, but more importantly, it should be easy to keep going.
Create a new Bly App, of which generally one should exist. If you find yourself passing the app object around alot, consider using plugins to organise your code instead.
var Bly = require('bly');
var app = new Bly.App();
Adds an action handler where:
options
- the action options object.Returns a reference (string) to which to identify this handler with.
name
- (required) the name of the action, the identifying string. For example RECEIVE_MESSAGES
. Can already be used before to register other handlers.handler
- (required) a function with the signature function (waitFor, payload)
used to generate the state mutations in stores.
waitFor
- a function passed to a handler which allows it to wait for other handlers using their reference. This is synchronous:
function(waitFor, payload) {
// do something
waitFor('otherHandler');
// continue doing things
}
payload
- an object that represents the payload of the action.ref
- an optional reference for this particular handler, which other handlers can use to waitFor
this handler. Defaults to be randomly generated.app.action({
name: 'RECEIVE_MESSAGES',
handler: function(waitFor, payload) {
waitFor('other-handler');
// do things
}
});
app.action({
name: 'RECEIVE_MESSAGES',
ref: 'other-handler'
handler: function(waitFor, payload) {
// do other things
}
});
Same as var ref = app.action(options)
but where actions
is an array of Action options. Returns an array of references to the handlers registered.
Inject an action into the system to be dispatched. The dispatching of an action is synchronous and only one action can be dispatched at a time. App has to be started with app.start
before actions can be injected.
action
- (required) the name of the action you want to inject. For example RECEIVE_MESSAGES
.payload
- the payload of the action, can be any value. Defaults to an empty object {}
var app = new Bly.App();
app.action({
name: 'RECEIVE_MESSAGES',
handler: myActionHandler
});
app.start();
app.inject('RECEIVE_MESSAGES');
Each injected action goes through a pre-defined life cycle constrained by the ideas of a Flux architecture.
onPreDispatch
event emitted.app.action
or plugin.action
.app.results
or plugin.results
.app.render
called with the gathered results.onPostDispatch
event emitted with the gathered results.Object where each key is a plugin name and the value are the exposed properties by that plugin using plugin.expose()
.
Register one or more plugins.
plugins
- (required) a plugin object or array of plugin objects, either manually constructed or plugin module.options
- optional options for registering, used by Bly to register the plugin and not passed to the plugin. Currently there are no options available, but reserved for future use.callback
- (required) function with signature function(err)
to be called once plugins have registered or failed to do so. Failure to register should be considered an unrecoverable event.To register a plugin this object is (or array of objects are) required containing the following:
pluginName
or name
- (required) name of the plugin, which must be unique. If using a module, using the name of the package is a pretty solid way to ensure it is doesn't conflict with others. pluginName
can be used if the plugin object is a function to prevent conflicts with Function.name
.multiple
- a boolean that indicates whether a plugin can be registered more than once. For safety defaults to false
.register
- (required) a function with signature function(plugin, options, next)
that is responsible for registering the pluginTo pass options to the plugin's register function, wrap the plugin object into an object containing:
plugin
- (required) plugin objectoptions
- object of options to be passed to the pluginRegister a function with signature function(report)
that allow for values to be passed to app.render
functions. Proven to be especially useful for rendering individual sections of apps in plugins, which can then be stitched together during the actual rendering of the app.
resultFn
- function with signature function(report)
where:
report
- function with signature function(key, value)
used to expose results using a where:
key
- (required) string by which made accessible on results
object
value
- value to be exposed on results object
Register a function that is to be called with the results of each dispatched actions, which is most useful for rendering your views to reflect the possible state changes made by the stores. If the app was started before registering the render function the render function will be called once straight away.
renderFunction
- (required) function with signature function(results)
where:
results
- object with results generated by functions registered with app.results
Start the app. For now this basically means actions can from then on be injected, in order to make sure all plugins and stores had a chance to set themselves up in working order. Would also be the point where in the future we can add more safety regarding the correct configuration of an app, like validating that stores are only listening for actions that the system knows off.
Retrieve a reference to a store instance
storeName
- name of the store to retrieve the instance for.Retrieve a reference to the the global stores object, which contains all stores instance indexed by storeName.
Register a store instance to be available to the rest of the app.
storeName
- (required) name of the store it can be referenced by.instance
- (required) value which represents your store instance.Set an entire object of store instances at once, indexed by store names.
storeMap
- (required) object of store instances, indexed by store names.options
- object of options containing any of the following:
merge
- whether to merge the store map with the existing register of stores instead of completely replacing it. Defaults to true
.Plugins, inspired by Hapi's plugins provide a way to organise your application's business logic, as well as extend apps with general purpose utilities (allthough many of the hooks for the latter still have to be discovered / determined). At the present it mostly enables you to think of your app as composition of various logical units, each covering their own domains, instead of one monolothic app.
A plugin consists of:
name
- (required) the plugin name used as an unique key to identify the plugin. When publishing plugins on npm it's a good idea to use their package name as name of the plugin in order to prevent conflicts.register
- (required) single entry point into the plugin's functionality. This is where a plugin declares what it should be doing.multiple
- a boolean that indicates whether a plugin can be registered more than once. For safety defaults to false
.Example of a plugin implementing a very simple store.
exports.name = 'messages';
exports.register = function(plugin, options, next) {
var messages = [];
plugin.action({
name: 'RECEIVE_MESSAGE',
handler: function(waitFor, message) {
messages.push(message);
}
});
plugin.stores('messages', messages);
next();
}
Register the plugin where:
plugin
- the registration interface to the app.options
- options object passed in app.register
.next
- function with signature function(err)
which should be called once registration of the plugin is complete. While this allows for asynchronous registration it also means that if next
is never called, the app will not configure itself properly. Any errors passed should be considered unrecoverable events and should trigger application termination.A reference to the Bly
module used to create the app, so the plugin doesn't need to have Bly
as a dependency itself.
The version the Bly
module used.
Adds a handler for an action as described by app.action
Adds a function to be called after the app was started.
afterFunction
- (required) function which will be executed after the app starts (no arguments passed)Exposes a property to the app.plugins[pluginName]
object.
key
- (required) the key for which to expose the valuevalue
Inject an action into the app to be dispatched as described by app.inject
.
Register plugins with this app as described by app.register
.
Register a function that is to be called with the results of each dispatched actions. As described by app.render
.
Register a function with signature function(report)
that allow for values to be passed to app.render
functions. As described by app.results
.
Interface to setting and getting store as described by app.stores
.
FAQs
Flux app framework with hapi like interface
We found that bly demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer 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.
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.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.