Skip to content

An SDK for building decentralized web apps with DIDs, VCs, and DWNs.

License

Notifications You must be signed in to change notification settings

amika-sq/web5-js

 
 

Repository files navigation

🎉 We're participating in Hacktoberfest 2023! 🎉

Want to contribute during Hacktoberfest? We'd love to have you! Dive in, and your contributions could earn you some exclusive rewards.

The first 20 contributors to successfully merge a PR will secure exclusive swag of their choosing from our TBD shop — we're in the midst of uploading new swag! Keep an eye on our leaderboard issue to see where you rank! ⭐️

🚀 Gear up for a month packed with exciting events! 🎉

  • Mark your calendars for our Hacktoberfest Launch event on October 2nd.
  • Stay in the loop - keep an eye on our Discord calendar and pop into our events-and-updates channel regularly! You won't want to miss out!

Hacktoberfest Guidelines:

  • Ensure your contribution is meaningful and fits within the scope of our project, by reading an open issue in its entirety before diving in.
  • Check out our good-first-issue and hacktoberfest labels in the issues section.
  • Join our Discord: Connect with the community, stay up to date with Hacktoberfest events/prizes, and discuss Hacktoberfest contributions on our Discord server. Click here to join.
  • Always be respectful and follow our code of conduct.
  • If in doubt about what to contribute, reach out to maintainers by raising a question in the relevant issue or specified discord channel.
  • Other participating TBD Repos:

What is Hacktoberfest?

Celebrate the 10th anniversary of Hacktoberfest this year! Hosted annually every October, Hacktoberfest is a month-long event sponsored by DigitalOcean, GitHub, and various other partners, championing open-source contributions.

⭐️ If you're new to Hacktoberfest, you can learn more and register to participate here. Registration is from September 26th- October 31st.

New Contributor? Welcome! 🌟

We wholeheartedly embrace new contributors to our community. Remember, every expert was once a beginner, and we understand the initial hurdles you might feel. Here’s how you can dive in:

  • Join Our Discord Channel:
    • Once inside, check out the Hacktoberfest section. This has all you need: resources, guidelines, and a checklist to help you make your first hacktoberfest contribution.
  • Feeling Anxious or Unsure? Find a Buddy!:
    • Head over to our hack-together section on Discord. It's perfectly normal to feel a tad overwhelmed or even the impostor syndrome on your first go. In this space, you can partner with someone to collaborate, share thoughts, or jointly tackle an issue. You know what they say, two heads are better than one!
  • Dive In:
    • Skim through our open issues and pick one you vibe with. And if you're on the fence about anything, don't hesitate to ask. Your new community is here to assist and walk with you every step of the way.
    • Mark your calendars for our Hacktoberfest Launch event on October 2nd.
    • Stay in the loop - keep an eye on our Discord calendar and pop into our #events-and-updates channel regularly! You won't want to miss out!

Your contribution, be it big or minuscule, carries immense value. We eagerly await to see the waves you'll make in our community! 🚀

Here's to a thrilling Hacktoberfest voyage with us! 🎉

Web5 JS SDK

NPM Build Status Coverage License Chat

Making developing with Web5 components at least 5 times easier to work with.

⚠️ WEB5 JS SDK IS CURRENTLY IN TECH PREVIEW ⚠️

The SDK is currently still under active development, but having entered the Tech Preview phase there is now a drive to avoid unnecessary changes unless backwards compatibility is provided. Additional functionality will be added in the lead up to 1.0 final, and modifications will be made to address issues and community feedback.

Table of Contents

Introduction

Web5 consists of the following components:

  • Decentralized Identifiers
  • Verifiable Credentials
  • DWeb Node personal datastores

The SDK sets out to gather the most oft used functionality from all three of these pillar technologies to provide a simple library that is as close to effortless as possible.

Running online environment

Interested in contributing instantly? You can make your updates directly without cloning in the running CodeSandbox environment.

Edit in CodeSandbox

Installation

NPM

npm install @web5/api

CDNs

https://unpkg.com/@web5/[email protected]/dist/browser.js
https://cdn.jsdelivr.net/npm/@web5/[email protected]/dist/browser.mjs

Usage

Importing the SDK

import { Web5 } from "@web5/api";

or

import { Web5 } from CDN_LINK_HERE;

Additional Steps

This SDK relies indirectly on the @noble/ed25519 and @noble/secp256k1 packages. Therefore, in certain environments, you'll need to perform additional steps to make it work.

  • Node.js <= 18
// node.js 18 and earlier,  needs globalThis.crypto polyfill
import { webcrypto } from "node:crypto";
// @ts-ignore
if (!globalThis.crypto) globalThis.crypto = webcrypto;
  • React Native:
// If you're on react native. React Native needs crypto.getRandomValues polyfill and sha512
import "react-native-get-random-values";
import { hmac } from "@noble/hashes/hmac";
import { sha256 } from "@noble/hashes/sha256";
import { sha512 } from "@noble/hashes/sha512";
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
ed.etc.sha512Async = (...m) => Promise.resolve(ed.etc.sha512Sync(...m));

secp.etc.hmacSha256Sync = (k, ...m) =>
  hmac(sha256, k, secp.etc.concatBytes(...m));
secp.etc.hmacSha256Async = (k, ...m) =>
  Promise.resolve(secp.etc.hmacSha256Sync(k, ...m));

API Documentation

Web5.connect(options)

Enables an app to request connection to a user's local identity app (like a desktop or mobile agent - work is underway for reference apps of each), or generate an in-app DID to represent the user (e.g. if the user does not have an identity app).

NOTE: The outputs of this method invocation will be used throughout the other API methods below.

const { web5, did: myDid } = await Web5.connect();

options (optional)

An object which may specify any of the following properties:

  • agent - Web5Agent instance (optional): an instance of a Web5Agent implementation. Defaults to creating a local Web5UserAgent if not provided.

  • appData - AppDataStore instance (optional): an instance of an AppDataStore implementation. Defaults to a LevelDB-backed store with an insecure, static unlock passphrase if not provided. To allow the end user to enter a secure passphrase of their choosing, provide an initialized AppDataVault.

  • connectedDid - string (optional): an existing DID to connect to.

  • sync - string (optional): enable or disable synchronization of DWN records between local and remote DWNs. Sync defaults to running every 2 minutes and can be set to any value accepted by ms. To disable sync set to 'off'.

  • techPreview - object (optional): an object that specifies configuration parameters that are relevant during the Tech Preview period of Web5 JS and may be deprecated in the future with advance notice.

    • dwnEndpoints - array (optional): a list of DWeb Node endpoints to define in the DID created and returned by Web5.connect(). If this property is omitted, during the Tech Preview two nodes will be included by default (e.g., ['https://dwn.tbddev.org/dwn0', 'https://dwn.tbddev.org/dwn3']).

    For example:

    const { web5, did: myDid } = await Web5.connect({
      techPreview: {
        dwnEndpoints: ["https://dwn.your-domain.org/"],
      },
    });

Response

An invocation of Web5.connect() produces the following items in response:

  • web5 - Web5 instance: A class instance that enables access to a locally running DWeb Node, DID interaction methods, and other capabilities related to the connected DID.
  • did - string: The DID that was created or attained connection to.

Record instances from responses

Every modifying method (create, write, etc.) and the entries from queries return an instance of a Record class, which is a representation of the Record(s) being referenced.

Each Record instance has the following instance properties: id, attestation, contextId, dataFormat, dateCreated, encryption, interface, method, parentId, protocol, protocolPath, recipient, schema, dataCid, dataSize, dateModified, datePublished, and published.

Note The id property is a unique identifier based on the record entry's composition. All entries across all records are deterministically unique.

Each Record instance has the following instance methods:

  • data - object: an object with the following convenience methods that read out the data of the record entry in the following formats:
    • text - function: produces a textual representation of the data.
    • json - function: if the value is JSON data, this method will return a parsed JSON object.
    • stream - function: returns the raw stream of bytes for the data.
  • send - function: sends the record the instance represents to the DWeb Node endpoints of a provided DID.
  • update - function: takes in a new request object matching the expected method signature of a write and overwrites the record. This is a convenience method that allows you to easily overwrite records with less verbosity.
  • delete - function: generates a delete entry tombstone for the record. This is a convenience method that allows you to easily delete records with less verbosity.

web5.dwn.records.query(request)

Method for querying either the locally connected DWeb Node or any remote DWeb Node specified in the from property.

// This invocation will query the user's own DWeb Nodes
const { records } = await web5.dwn.records.query({
  message: {
    filter: {
      schema: "https://schema.org/Playlist",
      dataFormat: "application/json",
    },
  },
});

console.log(records); // an array of record entries from Bob's DWeb Nodes

// This invocation will query Bob's DWeb Nodes
const { records } = await web5.dwn.records.query({
  from: "did:example:bob",
  message: {
    filter: {
      protocol: "https://music.org/protocol",
      schema: "https://schema.org/Playlist",
      dataFormat: "application/json",
    },
  },
});

console.log(records); // an array of record entries from Bob's DWeb Nodes

Request

The query request contains the following properties:

  • from - DID string (optional): the decentralized identifier of the DWeb Node the query will fetch results from.
  • message - object: the properties of the DWeb Node Message Descriptor that will be used to construct a valid record query:
    • filter - object: properties against which results of the query will be filtered:
      • recordId - string (optional): the record ID string that identifies the record data you are fetching.
      • protocol - URI string (optional): the URI of the protocol bucket in which to query.
      • protocolPath - string (optional): the path to the record in the protocol configuration.
      • contextId string (optional): the recordId of a root record of a protocol.
      • parentId string (optional): the recordId of a the parent of a protocol record.
      • recipient - string (optional): the DID in the recipient field of the record.
      • schema - URI string (optional): the URI of the schema bucket in which to query.
      • dataFormat - Media Type string (optional): the IANA string corresponding with the format of the data to filter for. See IANA's Media Type list here: https://www.iana.org/assignments/media-types/media-types.xhtml

web5.dwn.records.create(request)

Method for creating a new record and storing it in the user's local DWeb Node, remote DWeb Nodes, or another party's DWeb Nodes (if permitted).

// this creates a record and stores it in the user's local DWeb Node
const { record } = await web5.dwn.records.create({
  data: "Hello World!",
  message: {
    dataFormat: "text/plain",
  },
});

console.log(await record.data.text()); // logs "Hello World!"
const { status } = await record.send(myDid); // send the record to the user's remote DWeb Nodes
const { status } = await record.send("did:example:bob"); // send the newly generated record to Bob's DWeb Nodes

// this creates a record, but does not store it in the user's local DWeb Node
const { record } = await web5.dwn.records.create({
  store: false,
  data: "Hello again, World!",
  message: {
    dataFormat: "text/plain",
  },
});

const { status } = await record.send("did:example:bob"); // send the newly generated record to Bob's DWeb Nodes

Request

The create request object is composed as follows:

  • store - boolean (optional): tells the create function whether or not to store the record in the user's local DWeb Node. (you might pass false if you didn't want to retain a copy of the record for yourself)
  • data - text|object|file|blob: the data payload of the record.
  • message - object: The properties of the DWeb Node Message Descriptor that will be used to construct a valid record query:
    • protocol - URI string (optional): the URI of the protocol under which the record will be bucketed.
    • schema - URI string (optional): the URI of the schema under which the record will be bucketed.
    • dataFormat - Media Type string (optional): the IANA string corresponding with the format of the data the record will be bucketed. See IANA's Media Type list here: https://www.iana.org/assignments/media-types/media-types.xhtml

web5.dwn.records.write(request)

The create() method is an alias for write() and both can take the same request object properties.

web5.dwn.records.read(request)

Method for reading a record stored in the user's local DWeb Node, remote DWeb Nodes, or another party's DWeb Nodes (if permitted). The request takes a filter; if there is exactly one record matching the filter, the record and its data are returned. The most common filter is by recordId, but it is also useful to filter by protocol, contextId, and protocolPath.

// Reads the indicated record from the user's DWeb Nodes
const { record } = await web5.dwn.records.read({
  message: {
    filter: {
      recordId: "bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5",
    }
  },
});

console.log(await record.data.text()); // assuming the record is a text payload, logs the text

// Reads the indicated record from Bob's DWeb Nodes
const { record } = await web5.dwn.records.read({
  from: "did:example:bob",
  message: {
    filter: {
      recordId: "bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5",
    }
  },
});

console.log(await record.data.text()); // assuming the record is a text payload, logs the text

Request

The read request object is composed as follows:

  • from - DID string (optional): The DID of the DWeb Node the read request will fetch the indicated record from.
  • message - object: The properties of the DWeb Node Message Descriptor that will be used to construct a valid DWeb Node message.
    • filter - object: properties against which results of the query will be filtered:
      • recordId - string (optional): the record ID string that identifies the record data you are fetching.
      • protocol - URI string (optional): the URI of the protocol bucket in which to query.
      • protocolPath - string (optional): the path to the record in the protocol configuration.
      • contextId string (optional): the recordId of a root record of a protocol.
      • parentId string (optional): the recordId of a the parent of a protocol record.
      • recipient - string (optional): the DID in the recipient field of the record.
      • schema - URI string (optional): the URI of the schema bucket in which to query.
      • dataFormat - Media Type string (optional): the IANA string corresponding with the format of the data to filter for. See IANA's Media Type list here: https://www.iana.org/assignments/media-types/media-types.xhtml

web5.dwn.records.delete(request)

Method for deleting a record stored in the user's local DWeb Node, remote DWeb Nodes, or another party's DWeb Nodes (if permitted).

// Deletes the indicated record from the user's DWeb Node
const { record } = await web5.dwn.records.delete({
  message: {
    recordId: "bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5",
  },
});

// Deletes the indicated record from Bob's DWeb Node
const { record } = await web5.dwn.records.delete({
  from: "did:example:bob",
  message: {
    recordId: "bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5",
  },
});

Request

The delete request object is composed as follows:

  • from - DID string (optional): The DID of the DWeb Node the delete tombstone will be sent to.
  • message - object: The properties of the DWeb Node Message Descriptor that will be used to construct a valid DWeb Node message.
    • recordId - string: the required record ID string that identifies the record being deleted.

web5.dwn.protocols.configure(request)

Method for configuring a protocol definition in the DWeb Node of the user's local DWeb Node, remote DWeb Nodes, or another party's DWeb Nodes (if permitted).

const { protocol } = await web5.dwn.protocols.configure({
  message: {
    definition: {
      protocol: "https://photos.org/protocol",
      types: {
        album: {
          schema: "https://photos.org/protocol/album",
          dataFormats: ["application/json"],
        },
        photo: {
          schema: "https://photos.org/protocols/photo",
          dataFormats: ["application/json"],
        },
        binaryImage: {
          dataFormats: ["image/png", "jpeg", "gif"],
        },
      },
      structure: {
        album: {
          $actions: [
            {
              who: "recipient",
              can: "read",
            },
          ],
        },
        photo: {
          $actions: [
            {
              who: "recipient",
              can: "read",
            },
          ],
          binaryImage: {
            $actions: [
              {
                who: "author",
                of: "photo",
                can: "write",
              },
            ],
          },
        },
      },
    },
  },
});

protocol.send(myDid); // sends the protocol configuration to the user's other DWeb Nodes.

Request

The configure request object is composed as follows:

  • message - object: The properties of the DWeb Node Message Descriptor that will be used to construct a valid DWeb Node message.
    • definition - object: an object that defines the enforced composition of the protocol.
      • protocol - URI string: a URI that represents the protocol being configured.
      • types - object: an object that defines the records that can be used in the structure graph of the definition object. The following properties are optional constraints you can set for the type being defined:
        • schema - URI string (optional): the URI of the schema under which the record will be bucketed.
        • dataFormats - Media Type string[] (optional): Array of the IANA strings corresponding with the formats of the data the record will be bucketed. See IANA's Media Type list here: https://www.iana.org/assignments/media-types/media-types.xhtml
      • structure - object: an object that defines the structure of a protocol, including data relationships and constraints on which entities can perform various activities. Fields under the structure object of the Protocol definition are expected to be either type references matching those defined in the types object. The type structures are recursive, so types form a graph and each type can have within it further attached types or the following rule statements that are all denoted with the prefix $:
        • $actions - array: one or more rule objects that expose various allowed actions to actors (author, recipient), composed as follows:
          • who - string: the actor (author, recipient) that is being permitted to invoke a given action.
          • of - string: the protocol path that refers to the record subject. Using the above example protocol, the protocol path to binaryImage would be photo/binaryImage.
          • can - string: the action being permitted by the rule.

web5.dwn.protocols.query(request)

Method for querying a DID's DWeb Nodes for the presence of a protocol. This method is useful in detecting what protocols a given DID has installed to enable interaction over the protocol.

const { protocols } = await web5.dwn.protocols.query({
  message: {
    filter: {
      protocol: "https://music.org/protocol",
    },
  },
});

console.log(protocols); // logs an array of protocol configurations installed on the user's own DWeb Node

const { protocols } = await web5.dwn.protocols.query({
  from: "did:example:bob",
  message: {
    filter: {
      protocol: "https://music.org/protocol",
    },
  },
});

console.log(protocols); // logs an array of protocol configurations installed on Bob's DWeb Node

Request

The query request must contain the following:

  • from - DID string (optional): the decentralized identifier of the DWeb Node the query will fetch results from.
  • message - object: The properties of the DWeb Node Message Descriptor that will be used to construct a valid record query:
    • filter - object (optional): properties against which results of the query will be filtered:
      • protocol - URI string (optional): the URI of the protocol bucket in which to query.

web5.did.create(method, options)

The create method under the did object enables generation of DIDs for a supported set of DID Methods ('ion'|'key'). The output is method-specific, and handles things like key generation and assembly of DID Documents that can be published to DID networks.

NOTE: You do not usually need to manually invoke this, as the Web5.connect() method already acquires a DID for the user (either by direct creation or connection to an identity agent app).

const myDid = await Web5.did.create("ion");

Project Resources

Resource Description
CODEOWNERS Outlines the project lead(s)
CODE_OF_CONDUCT.md Expected behavior for project contributors, promoting a welcoming environment
CONTRIBUTING.md Developer guide to build, test, run, access CI, chat, discuss, file issues
GOVERNANCE.md Project governance
LICENSE Apache License, Version 2.0

About

An SDK for building decentralized web apps with DIDs, VCs, and DWNs.

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 81.9%
  • JavaScript 12.8%
  • HTML 5.3%