ssb-crut
Easily mint CRUD (Create, Read, Update, Delete) methods for scuttlebutt records!
Note there is no Delete, so instead we have T for Tombstone (CRUT!)
Example usage
const Crut = require('ssb-crut')
const Overwrite = require('@tangle/overwrite')
const SimpleSet = require('@tangle/simple-set')
const spec = {
type: 'gathering',
props: {
title: Overwrite(),
description: Overwrite(),
attendees: SimpleSet()
}
}
const crut = new Crut(ssb, spec)
crut.create(
{
title: 'Ahau launch party',
attendees: { add: ['Mix'] },
recps: ['%A9OUzXtv7BhaAfSMqBzOO6JC8kvwmZWGVxHDAlM+/so=.cloaked']
},
(err, gatheringId) => {
}
)
crut.update(
gatheringId,
{
description: "Let's celebrate this new phase!",
attendees: { add: ['Cherese'] }
},
(err, updateId) => {
crut.read(gatheringId, (err, gathering) => {
})
}
)
Requirements
Requires and ssb server with ssb-backlinks
installed.
Optionally, if you want to make private (encrypted) records, you will need to have a plugin installed
which knows how to handle your recps
ssb-tribes
(recommended) for records stored in a private group, or direct messagesssb-private1
for records as direct messages
API
new CRUT(ssb, spec) => crut
Takes ssb
, a scuttelbutt server instance and a spec
and returns an crut instance
with methods for mutable records.
A spec
is an Object with properties:
spec.type
String - directly related to the type
field that will occur on messagesspec.props
Object
- defines how the mutable parts of the record will behaved.
- each property is expected to be an instance of a tangle strategy (e.g.
@tangle/simple-set
) - reserved props:
['type', 'recps', 'tangle', 'tombstone']
Optional properties:
crut.create(allProps, cb)
Makes a new record, and calls back with the id
of that record.
allProps
Object
- none/ some/ all of the properties declared in
spec.props
- none/ some/ all of the properties declared in
spec.staticProps
recps
Array (optional) a list of recipients who this record will be encrypted to. Once this is set on create, it cannot be updatedallowPublic
Boolean (optional) for if you have ssb-guard-recps
installed and want to explicitly allow a public message through
Notes:
- if
cb
is not passed, a Promise is returned instead.
crut.read(id, cb)
Takes a record id and calls back with a Record.
A tangle here is a collection of messages linked in a directed acyclic graph.
Each of thee messages contains an "operational transform" which is an
instuction about how to update the record state.
Transformations are concatenated (added up) while traversing the graph.
For a tangle made up of messages linked like this:
A << root
/ \
B C << concurrent updates
|
D << an update which is also a tip
Then the reduced Record would look like:
{
key: A,
type,
...staticProps,
states: [
{
key: D,
...props
},
{
key: B,
...props
}
}
}
There will be 1 or more "states" depending on whether the tangle is a in a
branched / forked state at the moment.
The state of the props returned are "riefied" (meaning has been made real),
because often the transformation format is optimised for mathematical properties,
but not very human friendly.
Notes:
states
is sorted "most recent" to "least recent" by the tip messages's declared timestamp.- if
cb
is not passed, a Promise is returned instead.
crut.update(id, props, cb)
Updates record id
.
props
Object can have properties
- all/ some/ none of the props declared in
spec.props
allowPublic
Boolean (optional) for if you have ssb-guard-recps
installed and want to explicitly allow a public message through
The props
provided are used to generate a transformation which is then checked with isValidUpdate
(if provided), they are:
Message contents are also checked against isUpdate
before publishing.
Calls back with the key of the update message published.
Notes:
crut.tombstone(id, opts, cb)
A convenience helper mainly here to put the T in CRUT.
opts
Object with properties:
reason
String (optional) give a reason for why you're tombstoning the recordundo
Boolean (optional) set to true
to remove the tombstoneallowPublic
Boolean (optional) for if you have ssb-guard-recps
installed and want to explicitly allow a public message through
Calls back with the key of the update message which tombstoned.
Notes:
- if
cb
is not passed, a Promise is returned instead.
Using spec.arbitraryRoot with Private Groups
If you set spec.arbitraryRoot
to true, then you can use a groupId
that you're a part of and ssb-crut
will automatically root your record at the group init message.
The methods you can do this with are:
crut.updateGroup(groupId, props, cb)
crut.readGroup(groupId, cb)
crut.tombstoneGroup(groupId, opts, cb)
Reminder there is no crut.create
when you have an arbitraryRoot
TODO
crut.update
does not currently publish merges
- currently extends the tip with most recent activity
- want to change this in the future but @tangle/reduce will needs more work