Secret-Stack provides a minimal core for creating peer-to-peer networks like Secure-Scuttlebutt. It is highly extensible via plugins.
Plugins are simply NodeJS modules that export an object
of form { name, version, manifest, init }
.
// bluetooth-plugin.js
module.exports = {
name: 'bluetooth',
needs: ['conn'],
version: '5.0.1',
manifest: {
localPeers: 'async',
updates: 'source'
},
init: (api, opts) => {
// .. do things
// In opts, only opts.bluetooth and opts.global are available
// return things promised by the manifest:
return {
localPeers, // an async function (takes a callback)
updates // a function which returns a pull-stream source
}
}
}
Plugins are then added to a Secret-Stack
instance using the .use
method.
// index.js
var SecretStack = require('secret-stack')
var App = SecretStack({ global: { appKey: '1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=' } })
.use(require('./bluetooth-plugin'))
var app = App()
The plugin has now been mounted on the secret-stack
instance and
methods exposed by the plugin can be accessed at app.pluginName.methodName
(e.g. app.bluetooth.updates
)
Plugins can be used to for a number of different use cases, like adding a persistent underlying database (ssb-db) or layering indexes on top of the underlying store (ssb-links).
It becomes very easy to lump a bunch of plugins together and create a more sophisticated application.
var SecretStack = require('secret-stack')
var config = require('./some-config-file')
var Server = SecretStack({ global: { appKey: '1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=' } })
.use(require('ssb-db')) // added persistent log storage
.use(require('ssb-gossip')) // added peer gossip capabilities
.use(require('ssb-replicate')) // can now replicate other logs with peers
.use(require('ssb-friends')) // which peer's logs should be replicated
var server = Server(config) // start application
A valid plugin is an Object
of form { name, version, manifest, init }
A string that will also be used as the mount point for a plugin. a
plugin's methods with plugin.name = 'foo'
will be available at node.foo
on a
secret-stack
instance.
Names will also be automatically camelCased so plugin.name = "foo bar"
will be available at node.fooBar
.
A plugin.name
can also be an 'object
. This object will be merged
directly with the
An array of strings which are the names of other plugins that this plugin depends on. If those plugins are not present, then secret-stack will throw an error indicating that the dependency is missing.
Use this field to declare dependencies on other plugins, and this should facilitate the correct usage of your plugin.
NOTE - not currently used anywhere functionally
A plugin's current version number. These generally follow semver
guidelines.
When the secret-stack app is instantiated/ created, all init functions
of plugins will be called in the order they were registered with use
.
The init
function of a plugin will be passed:
api
- Object the secret-stack app so faropts
- configurations available to this plugin areopts.global
andopts[plugin.name]
permissions
- Object the permissions so farmanifest
- Object the manifest so far
If plugin.name
is a string, then the return value of init is mounted like api[plugin.name] = plugin.init(api, opts)
(If there's no plugin.name
then the results of init
are merged directly with the api
object!)
Note, each method on the api gets wrapped with hoox so that plugins may intercept that function.
An object containing the mapping of a plugin's exported methods and the
muxrpc
method type. See the
muxrpc#manifest documentation
for more details.
Any permissions provided will be merged into the main permissions, prefixed with the plugin name.
e.g. In this case we're giving anyone access to api.bluetooth.localPeers
,
and the permission would be listed 'bluetooth.localPeers'
module.exports = {
name: 'bluetooth',
version: '5.0.1',
manifest: {
localPeers: 'async',
updates: 'source'
},
permissions: {
anonymous: [ 'localPeers' ]
},
init: (api, opts) => {
// .. do things
// return things promised by the manifest:
return {
localPeers, // an async function (takes a callback)
updates // a function which returns a pull-stream source
}
}
}
A plugin can also be a function which returns an object. This is not currently recommended, as it's less clear to readers what the outcome is.