owned this note
owned this note
Published
Linked with GitHub
## Problem
The `$action` rules for `author` and `recipient` use the `of` keyword. The current implementation of `of` is limited and unintuitively specific given its generic name.
```json=
{
"$actions": [
{
"who": "author",
"of": "thread",
"can": "read"
},
{
"who": "recipient",
"of": "thread",
"can": "write"
}
]
}
```
## Proposal
We will refactor `of` from protocol definitions, turning it in an object with four options.
One alternative would be to have a single `of` object with two properties: `what` and `from`, wherein the combinations would be:
```javascript
{
"who": 'recipient',
"of": {
"what": 'foo/bar',
"in": 'any' | 'ancestors' | 'context' | 'descendants'
},
"can": 'write'
}
```
Or an even more English-like set of keywords
```javascript
{
"who": 'recipient',
"ofRecord": {
"atPath": 'foo/bar',
"inGroup": 'any' | 'ancestors' | 'context' | 'descendants'
},
"can": 'write'
}
```
### `'ancestors'`
`inGroup: 'ancestor'` is a renaming of the current behavior of `of`. `from: 'ancestor'` looks up the ancestor chain to find a record with a matching `who` and with `incomingMessage.protocolPath === ofAncestor`.
### `'descendants'`
`inGroup: 'descendants'` queries for descendants of the incoming record, looking for matching `who` and with `incomingMessage.protocolPath === action.ofRecord.atPath`. `action.ofRecord.atPath` will be the most troublesome to write a performant implementation because it involves first getting a list of children with matching `who` and `protocolPath`, then successively querying up each ancestor chain to ensure that the child record is actually a descendant of the incoming record message. Implementing this will also get us half way to #285.
Example: A podcaster stores episodes of their podcast in a DWN protocol. When a listener pays for an episode, the podcaster adds a `podcast/subscription` record with the listener as recipient. Using the `descendants` rule, the listener gains the ability to read the `podcast`.
```json=
"structure": {
"podcastSeries": {
"podcast": {
"$actions": [
{
"who": "recipient",
"ofRecord": {
"atPath":"podcastSeries/podcast/paywallUnlock",
"inGroup": "descendants"
},
"can": "read"
}
],
"paywallUnlock": {}
}
}
}
```
### `'context'`
`inGroup: 'context'` queries for records with matching `who`, `incomingMessage.protocolPath === action.ofRecord.AtPath`, and `incomingMessage.contextId === contextId`.
This addresses some of the use cases of `participants`. In a chat app, the protocol could allow any recipient of a `thread/invite` to write a `thread/chat` record within the same `thread`.
```json=
"structure": {
"thread": {
"chat": {
"$actions": [
{
"who": "recipient",
"ofRecord": {
"atPath": "thread/invite",
"inGroup": "context"
}
"can": "write"
}
]
},
"invite": {}
}
}
```
### `'any'`
`inGroup: 'any'` queries for any record in any context with matching `who` and `incomingMessage.protocolPath === action.ofRecord.atPath`. This could be useful in building a social media app with a list of "friends" who have certain access. In the below example, any `friend` may start a new `thread`.
```json=
"structure": {
"friend": {},
"thread": {
"$actions": [
{
"who": "recipient",
"ofRecord": {
"atPath": "friend",
"inGroup": "any"
},
"can": "write"
}
]
}
}
```