Skip to content

Rizina/dwn-sdk-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! 🎉

Decentralized Web Node (DWN) SDK

Code Coverage Statements Branches Functions Lines

Introduction

This repository contains a reference implementation of Decentralized Web Node (DWN) as per the specification. This specification is in a draft state and very much so a WIP. For the foreseeable future, a lot of the work on DWN will be split across this repo and the repo that houses the specification, which you can find here. The current implementation does not include all interfaces described in the DWN spec, but is enough to begin building test applications.

This project is used as a dependency by several other projects.

Proposals and issues for the specification itself should be submitted as pull requests to the spec repo.

Running online environment

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

Edit in CodeSandbox

Installation

If you are interested in using DWNs and web5 in your web app, you probably want to look at web5-js, instead of this repository. Head on over here: https://github.com/TBD54566975/web5-js.

For advanced users wishing to use this repo directly:

npm install @tbd54566975/dwn-sdk-js

Additional Steps

This package has dependency on @noble/ed25519 and @noble/secp256k1 v2, additional steps are needed for some environments:

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

Usage of DWN SDK in react native requires a bit of set up at the moment. To simplify, we've published an npm package that can be used to set everything up which you can find here. Follow the instructions there to get everything set up.

Usage in Browser:

dwn-sdk-js requires 2 polyfills: crypto and stream. we recommend using crypto-browserify and stream-browserify. Both of these polyfills can be installed using npm. e.g. npm install --save crypto-browserify stream-browserify

Vanilla HTML / JS

DWN SDK includes a polyfilled distribution that can imported in a module script tag. e.g.

<!DOCTYPE html>
<html lang="en">
<body>
  <script type="module">
    import { Dwn, DataStream, DidKeyResolver, Jws, RecordsWrite } from 'https://cdn.jsdelivr.net/npm/@tbd54566975/[email protected]/dist/bundles/dwn.js'
    import { MessageStoreLevel, DataStoreLevel, EventLogLevel } from 'https://cdn.jsdelivr.net/npm/@tbd54566975/[email protected]/dist/bundles/level-stores.js'

    const messageStore = new MessageStoreLevel();
    const dataStore = new DataStoreLevel();
    const eventLog = new EventLogLevel();
    const dwn = await Dwn.create({ messageStore, dataStore, eventLog });

    // generate a did:key DID
    const didKey = await DidKeyResolver.generate();

    // create some data
    const encoder = new TextEncoder();
    const data = encoder.encode('Hello, World!');

    // create a RecordsWrite message
    const recordsWrite = await RecordsWrite.create({
      data,
      dataFormat: 'application/json',
      published: true,
      schema: 'yeeter/post',
      authorizationSigner: Jws.createSigner(didKey)
    });

    // get the DWN to process the RecordsWrite
    const dataStream = DataStream.fromBytes(data);
    const result = await dwn.processMessage(didKey.did, recordsWrite.message, dataStream);

    console.log(result.status);
    console.assert(result.status.code === 202)

    await dwn.close()

  </script>
</body>

</html>

Webpack >= 5

add the following to the top level of your webpack config (webpack.config.js)

resolve: {
  fallback: {
    stream: require.resolve("stream-browserify"),
    crypto: require.resolve("crypto-browserify")
  }
}

Vite

add the following to the top level of your vite config (vite.config.js)

define: {
  global: 'globalThis'
},
resolve: {
  alias: {
    'crypto': 'crypto-browserify',
    'stream': 'stream-browserify'
  }
}

esbuild

we recommend using node-stdlib-browser instead of crypto-browserify and stream-browserify individually. Example usage:

import esbuild from 'esbuild'
import stdLibBrowser from 'node-stdlib-browser'
import polyfillProviderPlugin from 'node-stdlib-browser/helpers/esbuild/plugin'

import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);

esbuild.build({
  entryPoints: ['dwn-sdk-test.js'],
  platform: 'browser',
  bundle: true,
  format: 'esm',
  outfile: 'dist/dwn-sdk-test.js',
  inject      : [require.resolve('node-stdlib-browser/helpers/esbuild/shim')],
  plugins     : [polyfillProviderPlugin(stdLibBrowser)],
  define      : {
    'global': 'globalThis'
  }
})

Usage

API docs

import { Dwn, DataStream, DidKeyResolver, Jws, RecordsWrite } from '@tbd54566975/dwn-sdk-js';
import { DataStoreLevel, EventLogLevel, MessageStoreLevel } from '@tbd54566975/dwn-sdk-js/stores';

const messageStore = new MessageStoreLevel();
const dataStore = new DataStoreLevel();
const eventLog = new EventLogLevel();
const dwn = await Dwn.create({ messageStore, dataStore, eventLog });

// generate a did:key DID
const didKey = await DidKeyResolver.generate();

// create some data
const encoder = new TextEncoder();
const data = encoder.encode('Hello, World!');

// create a RecordsWrite message
const recordsWrite = await RecordsWrite.create({
  data,
  dataFormat: 'application/json',
  published: true,
  schema: 'yeeter/post',
  authorizationSigner: Jws.createSigner(didKey)
});

// get the DWN to process the RecordsWrite
const dataStream = DataStream.fromBytes(data);
const result = await dwn.processMessage(didKey.did, recordsWrite.message, dataStream);
console.log(result.status);

With a web wallet installed:

const result = await window.web5.dwn.processMessage({
  method: "RecordsQuery",
  message: {
    filter: {
      schema: "http://some-schema-registry.org/todo",
    },
    dateSort: "createdAscending",
  },
});

Custom Tenant Gating

By default, all DIDs are allowed as tenants. A custom tenant gate implementation can be provided when initializing the DWN.

import { Dwn, TenantGate, DataStoreLevel, EventLogLevel, MessageStoreLevel } from '@tbd54566975/dwn-sdk-js';

class CustomTenantGate implements TenantGate {
  public async isTenant(did): Promise<void> {
    // Custom implementation
    // returns `true` if the given DID is a tenant of the DWN; `false` otherwise
  }
}

const messageStore = new MessageStoreLevel();
const dataStore = new DataStoreLevel();
const eventLog = new EventLogLevel();
const tenantGate = new CustomTenantGate();
const dwn = await Dwn.create({ messageStore, dataStore, eventLog, tenantGate });

Custom Signature Signer

If you have the private key readily available, it is recommended to use the built-in PrivateKeySigner. Otherwise, you can implement a customer signer to interface with external signing service, API, HSM, TPM etc and use it for signing your DWN messages:

// create a custom signer
class CustomSigner implements Signer {
  public keyId = 'did:example:alice#key1';
  public algorithm = 'EdDSA'; // use valid `alg` value published in https://www.iana.org/assignments/jose/jose.xhtml
  public async sign (content: Uint8Array): Promise<Uint8Array> {
    ... // custom signing logic
  }
}

const authorizationSigner = new CustomSigner();

const options: RecordsWriteOptions = {
  ...
  authorizationSigner
};

const recordsWrite = await RecordsWrite.create(options);

Release/Build Process

The DWN JS SDK releases builds to npmjs.com. There are two build types: stable build and unstable build.

Stable Build

This is triggered manually by:

  1. Increment version in package.json in Semantic Versioning (semver) format.
  2. Merge the change into main branch
  3. Create a release from GitHub.

An official build with version matching the package.json will be published to npmjs.com.

Unstable Build

Every push to the main branch will automatically trigger an unstable build to npmjs.com for developers to experiment and test.

The version string contains the date as well as the commit hash of the last change.

An example version string:

0.0.26-unstable-2023-03-16-36ec2ce

  • 0.0.26 came from version in package.json
  • 2023-03-16 indicates the date of March 16th 2023
  • 36ec2ce is the commit hash of the last change

Some projects that use this library:

Architecture

Architecture of DWN SDN

NOTE: The diagram is a conceptual view of the architecture, the actual component abstraction and names in source file may differ.

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
Q_AND_A.md Questions and answers on DWN

About

Decentralized Web Node (DWN) Reference implementation

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 98.3%
  • JavaScript 1.6%
  • Shell 0.1%