Skip to content

Commit

Permalink
Merge pull request #14 from decentralized-identity/develop
Browse files Browse the repository at this point in the history
chore: new release
  • Loading branch information
mirceanis authored Nov 8, 2019
2 parents 29c6ca1 + f2cc402 commit 8a2361c
Show file tree
Hide file tree
Showing 12 changed files with 12,591 additions and 5,273 deletions.
97 changes: 97 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
###############################################################
# References
###############################################################
version: 2.1
references:
restore-npm-cache: &restore-npm-cache
restore_cache:
keys:
# when lock file changes, use increasingly general patterns to restore cache
- npm-packages-v1-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}
- npm-packages-v1-{{ checksum "package.json" }}
- npm-packages-v1-

save-npm-cache: &save-npm-cache
save_cache:
paths:
- node_modules/
key: npm-packages-v1-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}

###############################################################
# Workflows
###############################################################
workflows:
# Trigger workflow for last commit (merge commits) to master
# Run unit tests for sanity and if all looks good run semantic release
# Semantic release will decide based on commit messages if another release is needed
# Always run unit tests on master
automatic-semantic-release:
jobs:
- verify-unit-tests:
filters:
branches:
only:
- master
- run-semantic-release:
requires:
- verify-unit-tests
filters:
branches:
only:
- master
tags:
# Would be good if we can ignore tagged commits but it won't trigger another build so it's fine
ignore: /.*/

# This gets triggers on every push to all branches except master
# It verifies the branch, runs unit tests and coverage
verify-test-build:
jobs:
- verify-unit-tests:
filters:
branches:
ignore:
- master

###############################################################
# Jobs
###############################################################

jobs:
verify-unit-tests:
working_directory: ~/project
docker:
- image: circleci/node:10
steps:
- checkout
- *restore-npm-cache
- run:
name: Install node modules
command: npm install
- *save-npm-cache
- run:
name: Run unit tests
command: npm run test-with-coverage
- run:
name: Run lint
command: npm run lint
- persist_to_workspace:
root: ~/project
paths:
- node_modules

run-semantic-release:
working_directory: ~/project
docker:
- image: circleci/node:10
steps:
- checkout:
path: ~/project
- attach_workspace:
at: ~/project
- run:
name: Semantic release
command: |
git config user.email "[email protected]"
git config user.name "uport-automation-bot"
npm run release
9 changes: 9 additions & 0 deletions .dependabot/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 1
update_configs:

- package_manager: "javascript"
directory: "/"
update_schedule: "live"
commit_message:
prefix: "chore"
include_scope: true
17 changes: 17 additions & 0 deletions .github/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: inactive-autoclose
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ node_modules
lib
.vscode/settings.json
coverage
.idea/

*.log

Expand Down
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"jsxBracketSameLine": false,
"trailingComma": "all",
"trailingComma": "none",
"tabWidth": 2,
"printWidth": 80,
"singleQuote": true,
Expand Down
14 changes: 14 additions & 0 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"tagFormat": "${version}",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/changelog", {
"changelogFile": "CHANGELOG.md"
}],
"@semantic-release/npm",
"@semantic-release/git",
"@semantic-release/github"
],
"branch": "master"
}
105 changes: 83 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Javascript DID Resolver
[![CircleCI](https://circleci.com/gh/decentralized-identity/did-resolver.svg?style=svg)](https://circleci.com/gh/decentralized-identity/did-resolver)
[![codecov](https://codecov.io/gh/decentralized-identity/did-resolver/branch/master/graph/badge.svg)](https://codecov.io/gh/decentralized-identity/did-resolver)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/6dc5e3f01b1148698b0378d771341253)](https://www.codacy.com/manual/uport-project/did-resolver?utm_source=github.com&utm_medium=referral&utm_content=uport-project/did-resolver&utm_campaign=Badge_Grade)


This library is intended as a simple common interface for javascript applications to resolve DID documents from Decentralized Identifiers (DIDs).

Expand All @@ -16,19 +20,33 @@ You now no longer register your DID resolvers using the global `registerMethod()

## Configure `Resolver` object

You are now required to preconfigure a resolver during instantiation:
You are now required to preconfigure a resolver during instantiation. The `Resolver` constructor expects a registry of methods mapped to a resolver function. For example:
```js
{
ethr: resolve,
web: resolve
}
```

Each method resolver should expose a function called `getResolver` which will return an object containing one of these key/value pairs. Then you can flatten them into one object to pass into the `Resolver` constructor.
```js
import { DIDResolver } from 'did-resolver'
import { Resolver } from 'did-resolver'
import ethr from 'ethr-did-resolver'
import web from 'web-did-resolver'
import sov from 'sov-did-resolver'

const resolver = new DIDResolver({
ethr,
web,
https: web // Override a did method type
//returns an object of { methodName: resolveFunction}
ethrResolver = ethr.getResolver()
webResolver = web.getResolver()

//If you are using multiple methods you need to flatten them into one object
const resolver = new Resolver({
...ethrResolver,
...webResolver,
})

//If you are using one method you can simply pass the result of getResolver( into the constructor
const resolver = new Resolver(ethrResolver)
```

## Resolving a DID document
Expand All @@ -42,34 +60,77 @@ resolver.resolve('did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX/some/path#fragme
const doc = await resolver.resolve('did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX/some/path#fragment=123')
```

## Implementing a DID method
## Caching

Each DID method will have it's own methods for looking up an identifier on it's respective blockchain or other decentralized storage mechanism.
Resolving DID Documents can be expensive. It is in most cases best to cache DID documents. Caching has to be specifically enabled using the `cache` parameter

A method implementer calls the `registerMethod('methodname', resolver)`. where `methodname` is the method identifier. The resolver is a function that receives a DID and a parsed version of the DID. It returns a ES6 Promise that looks up the DID document.
The built in cache uses a Map, but does not have an automatic TTL, so entries don't expire. This is fine in most web, mobile and serverless contexts. If you run a long running process you may want to use an existing configurable caching system.

The built in Cache can be enabled by passing in a `true` value to the constructor:

```js
export default async function myResolver (did, parsed, didResolver) {
console.log(parsed)
// {method: 'mymethod', id: 'abcdefg', did: 'did:mymethod:abcdefg/some/path#fragment=123', path: '/some/path', fragment: 'fragment=123'}
const didDoc = ...// lookup doc
// If you need to lookup another did as part of resolving this did document, the primary DIDResolver object is passed in as well
const parentDID = await didResolver.resolve(...)
//
return didDoc
})
const resolver = new DIDResolver({
ethr,
web
}, true)
```

Here is an example using `js-cache` which has not been tested.


The method resolver should register this so that just requiring it will register the method:
```js
var cache = require('js-cache')
const customCache : DIDCache = (parsed, resolve) => {
// DID spec requires to not cache if no-cache param is set
if (parsed.params && parsed.params['no-cache'] === 'true') return await resolve()
const cached = cache.get(parsed.didUrl)
if (cached !== undefined) return cached
const doc = await resolve()
cache.set(parsed, doc, 60000)
return doc
}

const resolver = new DIDResolver({
ethr,
web
}, customCache)
```

## Implementing a DID method

Each DID method will have it's own methods for looking up an identifier on it's respective blockchain or other decentralized storage mechanism.

To avoid misconfiguration, method implementers should export a `getResolver()` function. Which returns an object mapping the method name to a `resolve(did: string, parsed: ParsedDID, didResolver: DIDResolver)` function. e.g. `{ ethr: resolve }`.

the resolve function should accept a did string, and an object of type [ParsedDID](https://github.com/decentralized-identity/did-resolver/blob/develop/src/resolver.ts#L51)

```js
export function getResolver() {
async function resolve(
did: string,
parsed: ParsedDID,
didResolver: DIDResolver
): Promise<DIDDocument | null> {
console.log(parsed)
// {method: 'mymethod', id: 'abcdefg', did: 'did:mymethod:abcdefg/some/path#fragment=123', path: '/some/path', fragment: 'fragment=123'}
const didDoc = ...// lookup doc
// If you need to lookup another did as part of resolving this did document, the primary DIDResolver object is passed in as well
const parentDID = await didResolver.resolve(...)
//
return didDoc
}

return { myMethod: resolve }
}
```

The MyMethod `getResolver()` result could then be passed into the DIDResolver constructor. Note that it should be flattened if used with other methods as well.

```js
import { DIDResolver } from 'did-resolver'
import MyMethod from 'mymethod-did-resolver'

const resolver = new DIDResolver({
mymethod: MyMethod
})
const myResolver = MyMethod.getResolver()
const resolver = new DIDResolver(myResolver)
```

Loading

0 comments on commit 8a2361c

Please sign in to comment.