@nidomiro/relation-tuple-parser
Version:
[](https://www.npmjs.com/package/@nidomiro/relation-tuple-parser)
120 lines (88 loc) • 3.28 kB
Markdown
# @nidomiro/relation-tuple-parser
[](https://www.npmjs.com/package/@nidomiro/relation-tuple-parser)
This library can parse a string representation of a Relation tuple to an object structure in typescript.
Relation tuples are used to evaluate permissions in "[Zanzibar: Google's Consistent, Global Authorization System](https://research.google/pubs/pub48190/)".
The [BNF](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form) of a valid Relation tuple is as follows:
```BNF
<relation-tuple> ::= <object>'#'relation'@'<subject> | <object>'#'relation'@('<subject>')'
<object> ::= namespace':'object_id
<subject> ::= subject_id | <subject_set>
<subject_set> ::= <object>'#'relation
```
Examples of valid strings:
```
namespace:object#relation@subjectId
namespace:object#relation@(subjectId)
namespace:object#relation@subjectNamespace:subjectObject#subjectRelation
namespace:object#relation@(subjectNamespace:subjectObject#subjectRelation)
```
The different parts of the Relation tuple can contain any character but `:#@()`.
A Relation tuple can easily be verbalised:
The Relation tuple `sharedFiles:a.txt#access@(dirs:b#access)` can be verbalised as "Anyone with `access` to `dirs:b`
has `access` to `sharedFiles:a.txt`".
After Parsing you get an object in the format:
```ts
interface SubjectSet {
namespace: string
object: string
relation: string
}
interface RelationTuple {
namespace: string
object: string
relation: string
subjectIdOrSet: string | SubjectSet
}
```
## Usage
```ts
import { parseRelationTuple } from '@nidomiro/relation-tuple-parser'
const result = parseRelationTuple('sharedFiles:a.txt#access@(dirs:b#access)')
const value = result.unwrapOrThrow()
/* value = {
namespace: 'sharedFiles',
object: 'a.txt',
relation: 'access',
subjectIdOrSet: {
namespace: 'dirs',
object: 'b',
relation: 'access',
},
}
*/
```
## With replacements
It is also possible to parse the Relation tuple in a structure where different placeholders can be replaced.
This is especially useful if you define a Guard via Decorators but require som dynamic replacements e.g. for the id of
the current user.
### Usage
```ts
import { parseRelationTupleWithReplacements } from '@nidomiro/relation-tuple-parser'
const result = parseRelationTupleWithReplacements(({ userId }) => `groups:admin#member@${userId}`)
/**
* Contains the "Template" of the Relation tuple with the replacements defined above.
* Calculate this once and use it on every evaluation.
*/
const valueWithreplacements = result.unwrapOrThrow()
/**
* Execute this at evaluation time (e.g. every incomming Request) to get the actual Relation tuple to evaluate against.
*/
const relationTuple = applyReplacements(valueWithreplacements, {
userId: 'my_user_id',
})
/* relationTuple = {
namespace: 'groups',
object: 'admin',
relation: 'member',
subjectIdOrSet: 'my_user_id',
}
*/
```
## Development
### Building
Run `nx build typescript` to build the library.
### Running unit tests
Run `nx test typescript` to execute the unit tests.
### Publish
Make sure you are logged into npm.
Run `nx publish typescript --tag latest --ver x.x.x` to publish to npm.