owned this note
owned this note
Published
Linked with GitHub
# 2022-11-25 ssb-submissions design
## Example Usage
```javascript
// ssb
// artefactCrut // could come from ssb.artefact.create
ssb.submission.registerHandler(isArtefact, artefactCrut)
ssb.submission.create({ id, { date: '2022-04-XX' }, cb)
// looks up record
// finds type "artefact", sees we have a registered artefactCrut,
// so knows how to validate/ execute stuff
```
Problems:
1. simulating a create/update
- Some things let you do a dry run that show you what the output would be
Ideas:
1. submitting a tombstone!
## API
### ssb.submission.registerHandler(crut)
register a handler for a message type
crut - crut instance (includes spec for record - has `type` and `isRoot` / `isUpdate`)
### ssb.submission.proposeEdit(recordId, details, { comment }, cb)
- recordId - id of a record you're wanting to edit. empty if you're proposing a new record
### ssb.submission.proposeNew(type, details, { comment }, cb)
- type - the type of the record being changed/created
- details - Fields (that match the recordId) filled in with proposed changes
### ssb.submission.read(id)
takes submission id, calls back with submission record
- accepted or not, details etc
### ssb.submission.showProposalResult(id, cb)
- id : submission id
for when we want to see what would happen if you applied the edit.
- algorithm
- 1. read the current record state
- 2. "predict" the record state if this submission was applied
- 3. highlight diff (changing fields)
- 1. The recordId is null
- 2. "predict" what the new thing would look like
- 3. Wouldn't highlight diff
### ssb.submission.accept(id, { comment }, cb)
- id - submission id
- cb - callback of signature (err, recordEditId)
### ssb.submission.reject(id, { comment }, cb)
- id - submission id
- cb - callback of signature (err)
### ssb.submission.tombstone
### ssb.submission.list
---
Register handler pseudocode
```javascript
const submissionCrut = new CRUT(ssb, submissionSpec)
const handlers = []
const findCrut = (content) => {
const handler = handlers.find(h => h[0]({ type }))
if (handler) return handler[1]
}
const API = {
registerHandler (crut) {
const isType = content => content.type === crut.spec.type
handlers.push([isType, crut])
},
proposeNew (type, details, { comment }, cb) {
const crut = findCrut({ type })
if (!crut) return cb(new Error('unknown type: ' + type))
const isValid = crut.isRoot
// check it's a well formed
if (!isValid(details)) return cb(new Error(isValid.errorString))
const content = {
id: null
recordType: type,
submission: details,
comment
}
submissionCrut.create(content, cb)
// publish message of type: submission/artefact
},
proposeEdit (recordId, details, { comment }, cb) {
if(!recordId) return cb(new Error('Invalid recordId: ' + recordId))
const targetRecord = lookUp(recordId) // is there something that can lookup a record of any type?
if(!targetRecord) // not found, tombstoned, etc
return cb(new Error('Invalid record: ' + recordId))
const crut = findCrut({ targetRecord.type }) // Is there a lookup that can get the crut of a record directly?
if (!crut) return cb(new Error('unknown type: ' + targetRecord.type))
if (!crut.isValid(details) || !crut.isValidNextStep(details)) return cb(new Error(isValid.errorString))
const content = {
id: recordId
recordType: type,
submission: details,
comment
}
submissionCrut.create(content, cb)
}
}
```
---
### Test cases:
Simple:
- [x] - ProposeNew,Edit,Tombstone
- [x] - Accepting/rejecting proposal
- [x] - Proposing identity new/edit
- [ ] - ~~checking other proposal status: pending/invalid/obsolete/viewed...~~
- [ ] - ~~Kaitiaki creating submission~~
- [ ] - Reading submission
- [ ] - Details
- [ ] - type
- [ ] - status
- [ ] - approvedBy
- [ ] - Differences (similar to details but uses simulation)
RegisterHandler
- [ ] - without crut,
- [ ] - with incorrect crut,
- [ ] - with multiple crut,
- [ ] - with profile (not unique type)
Expect errors:
- [x] - Editing a profile that doesn't exist
- [x] - Editing a profile that hasn't been recieved by kaitiaki
- [ ] - Editing a profile from a different group
- [x] - Editing null recordId
- [x] - Invalid details
- [ ] - Invalid nextState
- [ ] - Proposal that doesn't resolve conflict
- [ ] - complex: kaitiaki having different tips compared to submitter
- [x] - Invalid type
- [ ] - editing tombstoned profile
- [x] - Accepting a submission that has been tombstoned
- [x] - Accepting a submission that doesn't exist
Complex:
- [ ] - Rejecting an already accepted proposal (and vis versa)
- [ ] - crut with special isValidNextStep
- [ ] - Multiple kaitiaki accepting/rejecting
- [ ] - Non-kaitiaki accepting/declining
- [ ] - Simultaneous accept+reject, i.e. multiple tips
- [ ] - then merging tips
- [ ] - Simulating/reading rejected/tombstoned/invalid submissions