Install | Usage | Example | Data Standards | API Docs
3box-js
This is a library which allows you to set, get, and remove private and public data associated with an ethereum account. It can be used to store identity data, user settings, etc. by dapps that use a web3 enabled browser. The data will be retrievable as long as the user has access to the private key for the used ethereum account. The data is encrypted and can not be read by any third party that the user hasn't authorized. There is one shared space for data which all authorized dapps access by default, then there are spaces which dapps have to request explicit consent to access.
Getting Started
Installation
Install 3box in your npm project:
$ npm install 3box
Usage
Import 3Box into your project
Import the 3box module
const Box = require('3box')
Import using the dist build in your html code
<script type="text/javascript" src="../dist/3box.js"></script>
Or optionally by loading remote copy from unpkg CDN.
<!-- The most recent version -->
<script src="https://unpkg.com/3box/dist/3box.js"></script>
<!-- The most recent minified version -->
<script src="https://unpkg.com/3box/dist/3box.min.js"></script>
<!-- Load specific versions by specifying the version as follows -->
<script src="https://unpkg.com/3box@<version>/dist/3box.js"></script>
Profiles API
Get the existing public profile of an address (or DID)
3Box allows users to create a public profile for their Ethereum address. In your dapp you might have multiple ethereum addresses that you would like to display a name, image, and other basic social metadata for. The getProfile
method allows you to fetch the public profile of any ethereum address (if it has one). This is a static method so you can call it directly from the Box object.
const profile = await Box.getProfile('0x12345abcde')
console.log(profile)
Update (get, set, remove) public and private profile data
3Box allows applications to create, read, update, and delete public and private data stored in a user's 3Box. To enable this functionality, applications must first open the user's 3Box by calling the openBox method. This method prompts the user to authenticate (sign-in) to your dapp and returns a promise with a threeBox instance. You can only update (set, get, remove) data for users that have authenticated to and are currently interacting with your dapp. Below ethereumProvider
refers to the object that you would get from web3.currentProvider
, or window.ethereum
.
1. Authenticate users to begin new 3Box session
Calling the openBox method will open a new 3Box session. If the user's ethereum address already has a 3Box account, your application will gain access to it. If the user does not have an existing 3Box account, this method will automatically create one for them in the background.
const box = await Box.openBox('0x12345abcde', ethereumProvider)
2. Sync user's available 3Box data from the network
When you first open the box in your dapp all data might not be synced from the network yet. You should therefore add a listener using the onSyncDone
method. This will allow you to know when all the user's data is available to you. We advise against setting any data before this sync has happened. However, reading data before the sync is complete is fine and encouraged - just remember to check for updates once this callback is fired!
box.onSyncDone(yourCallbackFunction)
3. Interact with 3Box profile data
You can now use the box
instance object to interact with public and private data stored in the user's profile. In both the public and the private data store you use a key
to set a value
.
// use the public profile
// get
const nickname = await box.public.get('name')
console.log(nickname)
// set
await box.public.set('name', 'oed')
// remove
await box.public.remove('name')
// use the private store
// get
const email = await box.private.get('email')
console.log(email)
// set
await box.private.set('email', 'oed@email.service')
// remove
await box.private.remove('email')
Spaces API (Storage)
Open a space
A space is a named section of a users 3Box. Each space has both a public and a private store, and for every space you open the user has to grant explicit consent to view that space. This means that if your dapp uses a space that no other dapp uses, only your dapp is allowed to update the data and read the private store of that particular space. To open a space called narwhal
you simply call:
const space = await box.openSpace('narwhal')
Get, set, and remove space data
Interacting with data in a space is done in the same way as interacting with box.public
and box.private
(see here). For example:
const config = await space.private.get('dapp-config')
Threads API (Messaging)
Add message threads to your app
Threads are a shared datastore that enable decentralized communication between users, by allowing one or more users to post messages in a sequence. This functionality is great for adding commenting, chat, messaging, feed, and stream features to your application. Threads are saved within a space and users that join a thread (with the same name, in the same space) will be able to communicate in that thread.
For the fully detailed spec, view the documentation.
WARNING: this is an experimental feature, the API will likely change in the future!
Viewing a Thread
You can get all posts made in a thread without opening a space. This is great for allowing visitors of your site view comments made by other users. This is achieved by calling the getThread
method on the Box object.
const posts = await Box.getThread(spaceName, threadName)
console.log(posts)
However if applications want to add interactivity to the thread, such as allowing the user to post in a thread or follow updates in a thread, you will need to open their space to enable additional functionality.
Interacting with a Thread
1. Joining a thread
To post in a thread, a user must first join the thread.
const thread = await space.joinThread('myThread')
2. Posting to a thread
This allows the user to add a message to the thread. The author of the message will be the user's 3Box DID. When a user posts in a thread, they are automatically subscribed to the thread and it is saved in the space used by the application under the key thread-threadName
.
await thread.post('hello world')
3. Getting all posts in a thread
This allows applications to get the posts in a thread.
const posts = await thread.getPosts()
console.log(posts)
4. Listening for updates in thread
This allows applications to listen for new posts in the thread, and perform an action when this occurs, such as adding the new message to the application's UI.
thread.onNewPost(myCallbackFunction)
Example Application
You can quickly run and interact with some code by looking at the files in the /example
folder. You run the example with the following command:
$ npm run example:start
This runs a simple server at http://localhost:3000/
that serves the static example/index.html
file. This allows it easily interact with metamask. You can edit the example/index.html
file to try differnt code.
Optimize build for read-only 3Box API
If you only want to fetch profile data from 3Box's profile APIs you can optimize by importing only those functions or the API specific dist file. Since this includes minimal dependencies, file size is ~ 80kb vs 4+mb for the full build.
const { profileGraphQL, getProfile, getProfiles, getVerifiedAccounts } = require('3box/lib/api')
<script src="https://unpkg.com/3box/dist/3box.api.min.js"></script>
Data Standards
Dapps can store data about users that relate to only their dapp. However we encurage dapps to share data between them for a richer web3 experience. Therefore we have created Key Conventions in order to facilitate this. Feel free to make a PR to this file to explain to the community how you use 3Box!
Validate claims
Use the idUtils
module to validate claims. See
the did-jwt library for more details.
const { idUtils } = require('3box')
const claim = 'eyJ0eX...'
idUtils.verifyClaim(claim)
.then(valid => console.info('details:', valid)
.catch(err => console.error('claim verification failed:', err)
API Documentation
Box
Kind: global class
-
Box
- new Box()
- instance
-
static
-
.idUtils
-
.verifyClaim β
Object
-
.isMuportDID(address) β
*
|boolean
-
.isClaim(claim, opts) β
Promise.<boolean>
-
.verifyClaim β
-
.getProfile(address, opts) β
Object
-
.getProfiles(address, opts) β
Object
-
.getSpace(address, name, opts) β
Object
-
.getThread(space, name, opts) β
Array.<Object>
-
.listSpaces(address, opts) β
Object
-
.profileGraphQL(query, opts) β
Object
-
.getVerifiedAccounts(profile) β
Object
-
.openBox(address, ethereumProvider, opts) β
Box
-
.isLoggedIn(address) β
Boolean
-
.idUtils
new Box()
Please use the openBox method to instantiate a 3Box
box.public
Kind: instance property of Box
Properties
Name | Type | Description |
---|---|---|
public | KeyValueStore |
access the profile store of the users 3Box |
box.private
Kind: instance property of Box
Properties
Name | Type | Description |
---|---|---|
private | KeyValueStore |
access the private store of the users 3Box |
box.verified
Kind: instance property of Box
Properties
Name | Type | Description |
---|---|---|
verified | Verified |
check and create verifications |
box.spaces
Kind: instance property of Box
Properties
Name | Type | Description |
---|---|---|
spaces | Object |
an object containing all open spaces indexed by their name. |
Space
box.openSpace(name, opts) β Opens the space with the given name in the users 3Box
Kind: instance method of Box
Returns: Space
- the Space instance for the given space name
Param | Type | Description |
---|---|---|
name | String |
The name of the space |
opts | Object |
Optional parameters |
opts.consentCallback | function |
A function that will be called when the user has consented to opening the box |
opts.onSyncDone | function |
A function that will be called when the space has finished syncing with the pinning node |
box.onSyncDone(syncDone)
Sets the callback function that will be called once when the db is fully synced.
Kind: instance method of Box
Param | Type | Description |
---|---|---|
syncDone | function |
The function that will be called |
box.logout()
Closes the 3box instance and clears local cache. If you call this, users will need to sign a consent message to log in the next time you call openBox.
Kind: instance method of Box
Box.idUtils
A module to verify & validate claims
Kind: static property of Box
-
.idUtils
-
.verifyClaim β
Object
-
.isMuportDID(address) β
*
|boolean
-
.isClaim(claim, opts) β
Promise.<boolean>
-
.verifyClaim β
Object
idUtils.verifyClaim β Verify a claim and return its content. See https://github.com/uport-project/did-jwt/ for more details.
Kind: static property of idUtils
Returns: Object
- The validated claim
Param | Type | Description |
---|---|---|
claim | String |
|
opts | Object |
Optional parameters |
opts.audience | string |
The DID of the JWT's audience |
*
| boolean
idUtils.isMuportDID(address) β Check whether a string is a muport did or not
Kind: static method of idUtils
Returns: *
| boolean
- Whether the address is a muport did or not
Param | Type | Description |
---|---|---|
address | String |
A string containing a user profile address |
Promise.<boolean>
idUtils.isClaim(claim, opts) β Check whether a string is a valid claim or not
Kind: static method of idUtils
Returns: Promise.<boolean>
- whether the parameter is an actual claim
Param | Type | Description |
---|---|---|
claim | String |
|
opts | Object |
Optional parameters |
opts.audience | string |
The DID of the audience of the JWT |
Object
Box.getProfile(address, opts) β Get the public profile of a given address
Kind: static method of Box
Returns: Object
- a json object with the profile for the given address
Param | Type | Description |
---|---|---|
address | String |
An ethereum address |
opts | Object |
Optional parameters |
opts.addressServer | String |
URL of the Address Server |
opts.ipfs | Object |
A js-ipfs ipfs object |
opts.useCacheService | Boolean |
Use 3Box API and Cache Service to fetch profile instead of OrbitDB. Default true. |
opts.profileServer | String |
URL of Profile API server |
Object
Box.getProfiles(address, opts) β Get a list of public profiles for given addresses. This relies on 3Box profile API.
Kind: static method of Box
Returns: Object
- a json object with each key an address and value the profile
Param | Type | Description |
---|---|---|
address | Array |
An array of ethereum addresses |
opts | Object |
Optional parameters |
opts.profileServer | String |
URL of Profile API server |
Object
Box.getSpace(address, name, opts) β Get the public data in a space of a given address with the given name
Kind: static method of Box
Returns: Object
- a json object with the public space data
Param | Type | Description |
---|---|---|
address | String |
An ethereum address |
name | String |
A space name |
opts | Object |
Optional parameters |
opts.profileServer | String |
URL of Profile API server |
opts.metadata | String |
flag to retrieve metadata |
Array.<Object>
Box.getThread(space, name, opts) β Get all posts that are made to a thread.
Kind: static method of Box
Returns: Array.<Object>
- An array of posts
Param | Type | Description |
---|---|---|
space | String |
The name of the space the thread is in |
name | String |
The name of the thread |
opts | Object |
Optional parameters |
opts.profileServer | String |
URL of Profile API server |
Object
Box.listSpaces(address, opts) β Get the names of all spaces a user has
Kind: static method of Box
Returns: Object
- an array with all spaces as strings
Param | Type | Description |
---|---|---|
address | String |
An ethereum address |
opts | Object |
Optional parameters |
opts.profileServer | String |
URL of Profile API server |
Object
Box.profileGraphQL(query, opts) β GraphQL for 3Box profile API
Kind: static method of Box
Returns: Object
- a json object with each key an address and value the profile
Param | Type | Description |
---|---|---|
query | Object |
A graphQL query object. |
opts | Object |
Optional parameters |
opts.graphqlServer | String |
URL of graphQL 3Box profile service |
Object
Box.getVerifiedAccounts(profile) β Verifies the proofs of social accounts that is present in the profile.
Kind: static method of Box
Returns: Object
- An object containing the accounts that have been verified
Param | Type | Description |
---|---|---|
profile | Object |
A user profile object, received from the getProfile function |
Box
Box.openBox(address, ethereumProvider, opts) β Opens the 3Box associated with the given address
Kind: static method of Box
Returns: Box
- the 3Box instance for the given address
Param | Type | Description |
---|---|---|
address | String |
An ethereum address |
ethereumProvider | ethereumProvider |
An ethereum provider |
opts | Object |
Optional parameters |
opts.consentCallback | function |
A function that will be called when the user has consented to opening the box |
opts.pinningNode | String |
A string with an ipfs multi-address to a 3box pinning node |
opts.ipfs | Object |
A js-ipfs ipfs object |
opts.addressServer | String |
URL of the Address Server |
Boolean
Box.isLoggedIn(address) β Check if the given address is logged in
Kind: static method of Box
Returns: Boolean
- true if the user is logged in
Param | Type | Description |
---|---|---|
address | String |
An ethereum address |
KeyValueStore
Kind: global class
-
KeyValueStore
- new KeyValueStore()
-
.log β
Array.<Object>
-
.get(key) β
String
-
.getMetadata(key) β
Metadata
-
.set(key, value) β
Boolean
-
.remove(key) β
Boolean
new KeyValueStore()
Please use box.public or box.private to get the instance of this class
Array.<Object>
keyValueStore.log β Returns array of underlying log entries. In linearized order according to their Lamport clocks. Useful for generating a complete history of all operations on store.
Kind: instance property of KeyValueStore
Returns: Array.<Object>
- Array of ordered log entry objects
Example
const log = store.log
const entry = log[0]
console.log(entry)
// { op: 'PUT', key: 'Name', value: 'Botbot', timeStamp: '1538575416068' }
String
keyValueStore.get(key) β Get the value of the given key
Kind: instance method of KeyValueStore
Returns: String
- the value associated with the key, undefined if there's no such key
Param | Type | Description |
---|---|---|
key | String |
the key |
Metadata
keyValueStore.getMetadata(key) β Get metadata for for a given key
Kind: instance method of KeyValueStore
Returns: Metadata
- Metadata for the key, undefined if there's no such key
Param | Type | Description |
---|---|---|
key | String |
the key |
Boolean
keyValueStore.set(key, value) β Set a value for the given key
Kind: instance method of KeyValueStore
Returns: Boolean
- true if successful
Param | Type | Description |
---|---|---|
key | String |
the key |
value | String |
the value |
Boolean
keyValueStore.remove(key) β Remove the value for the given key
Kind: instance method of KeyValueStore
Returns: Boolean
- true if successful
Param | Type | Description |
---|---|---|
key | String |
the key |
Space
Kind: global class
new Space()
Please use box.openSpace to get the instance of this class
space.public
Kind: instance property of Space
Properties
Name | Type | Description |
---|---|---|
public | KeyValueStore |
access the profile store of the space |
space.private
Kind: instance property of Space
Properties
Name | Type | Description |
---|---|---|
private | KeyValueStore |
access the private store of the space |
Thread
space.joinThread(name, opts) β Join a thread. Use this to start receiving updates from, and to post in threads
Kind: instance method of Space
Returns: Thread
- An instance of the thread class for the joined thread
Param | Type | Description |
---|---|---|
name | String |
The name of the thread |
opts | Object |
Optional parameters |
opts.noAutoSub | Boolean |
Disable auto subscription to the thread when posting to it (default false) |
space.subscribeThread(name)
Subscribe to the given thread, if not already subscribed
Kind: instance method of Space
Param | Type | Description |
---|---|---|
name | String |
The name of the thread |
space.unsubscribeThread(name)
Unsubscribe from the given thread, if subscribed
Kind: instance method of Space
Param | Type | Description |
---|---|---|
name | String |
The name of the thread |
Array.<String>
space.subscribedThreads() β Get a list of all the threads subscribed to in this space
Kind: instance method of Space
Returns: Array.<String>
- A list of thread names
Thread
Kind: global class
-
Thread
- new Thread()
-
.post(message) β
String
-
.getPosts(opts) β
Array.<Object>
- .onNewPost(newPostFn)
new Thread()
Please use space.joinThread to get the instance of this class
String
thread.post(message) β Post a message to the thread
Kind: instance method of Thread
Returns: String
- The postId of the new post
Param | Type | Description |
---|---|---|
message | Object |
The message |
Array.<Object>
thread.getPosts(opts) β Returns an array of posts, based on the options. If hash not found when passing gt, gte, lt, or lte, the iterator will return all items (respecting limit and reverse).
Kind: instance method of Thread
Returns: Array.<Object>
- true if successful
Param | Type | Description |
---|---|---|
opts | Object |
Optional parameters |
opts.gt | String |
Greater than, takes an postId |
opts.gte | String |
Greater than or equal to, takes an postId |
opts.lt | String |
Less than, takes an postId |
opts.lte | String |
Less than or equal to, takes an postId |
opts.limit | Integer |
Limiting the number of entries in result, defaults to -1 (no limit) |
opts.reverse | Boolean |
If set to true will result in reversing the result |
thread.onNewPost(newPostFn)
Register a function to be called for every new post that is received from the network. The function takes one parameter, which is the post. Note that posts here might be out of order.
Kind: instance method of Thread
Param | Type | Description |
---|---|---|
newPostFn | function |
The function that will get called |
Verified
Kind: global class
-
Verified
- new Verified()
-
.DID() β
String
-
.github() β
Object
-
.addGithub(gistUrl) β
Object
-
.twitter() β
Object
-
.addTwitter(claim) β
Object
-
.email() β
Object
-
.addEmail(claim) β
Object
new Verified()
Please use box.verified to get the instance of this class
String
verified.DID() β Returns the verified DID of the user
Kind: instance method of Verified
Returns: String
- The DID of the user
Object
verified.github() β Verifies that the user has a valid github account Throws an error otherwise.
Kind: instance method of Verified
Returns: Object
- Object containing username, and proof
Object
verified.addGithub(gistUrl) β Adds a github verification to the users profile Throws an error if the verification fails.
Kind: instance method of Verified
Returns: Object
- Object containing username, and proof
Param | Type | Description |
---|---|---|
gistUrl | Object |
URL of the proof |
Object
verified.twitter() β Verifies that the user has a valid twitter account Throws an error otherwise.
Kind: instance method of Verified
Returns: Object
- Object containing username, proof, and the verifier
Object
verified.addTwitter(claim) β Adds a twitter verification to the users profile Throws an error if the verification fails.
Kind: instance method of Verified
Returns: Object
- Object containing username, proof, and the verifier
Param | Type | Description |
---|---|---|
claim | String |
A did-JWT claim ownership of a twitter username |
Object
verified.email() β Verifies that the user has a verified email account Throws an error otherwise.
Kind: instance method of Verified
Returns: Object
- Object containing username, proof, and the verifier
Object
verified.addEmail(claim) β Adds an email verification to the users profile Throws an error if the verification fails.
Kind: instance method of Verified
Returns: Object
- Object containing username, proof, and the verifier
Param | Type | Description |
---|---|---|
claim | String |
A did-JWT claim ownership of an email username |