An open API service indexing awesome lists of open source software.

https://github.com/decentralized-identity/didwebvh-ts

An implementation in Typescript of did:webvh
https://github.com/decentralized-identity/didwebvh-ts

citz digital-trust ditp dts trust-over-ip verifiable-credentials verifiable-organization-network von wg-id

Last synced: 11 days ago
JSON representation

An implementation in Typescript of did:webvh

Awesome Lists containing this project

README

          

# `didwebvh-ts`

`didwebvh-ts` provides developers with a comprehensive library for working with Decentralized Identifiers (DIDs) following the `did:webvh` method specification. This Typescript-based toolkit is designed to facilitate the integration and management of DIDs within web applications, enabling secure identity verification and authentication processes. It includes functions for creating, resolving, updating and deactivating DIDs by managing DID documents. The package is built to ensure compatibility with the latest web development standards, offering a straightforward API that makes it easy to implement DID-based features in a variety of projects.

## Summary

The `didwebvh-ts` implementation of the [`did:webvh`]('https://identity.foundation/didwebvh/') specification aims to be compatible with the `did:webvh` v1.0 specification.

## Examples

The `examples` directory contains sample code demonstrating how to use the library:

- **Resolver Examples**: The `examples` directory includes two resolver implementations:
- `elysia-resolver.ts`: (`bun run example:resolver`) A resolver built with the Elysia web framework
- `express-resolver.ts`: A resolver built with Express.js
Both examples demonstrate how to implement a DID resolver with different web frameworks. See the [Examples README](./examples/README.md) for more information.
- **Signer Example**: The `examples/signer.ts` (`bun run example:signer`) file demonstrates how to implement a custom signer using `AbstractCrypto`.

## Prerequisites

Install [bun.sh](https://bun.sh/)

```bash
curl -fsSL https://bun.sh/install | bash
```

## Install dependencies

```bash
bun install
```

## Local development setup

When running the examples from the source checkout, Bun needs to resolve the `didwebvh-ts` package name to your local code. Run the following once per clone:

```bash
bun run build # generate the dist/ artifacts
bun link # register the local package globally
bun link didwebvh-ts # create a symlinked dependency in node_modules
```

After linking, you can start the resolver example:

```bash
bun run server
```

If you ever need to refresh the build (for example after local code changes), rerun `bun run build`. The `bun link` commands only need to be repeated if you remove the symlink or clone the repo again.

## Available Commands

The following commands are defined in the `package.json` file:

1. `dev`: Run the Elysia resolver example in development mode with debugging enabled.

```bash
bun run dev
```

This command runs: `bun --watch --inspect-wait ./examples/elysia-resolver.ts`

1. `server`: Run the Elysia resolver example in watch mode for development.

```bash
bun run server
```

This command runs: `bun --watch ./examples/elysia-resolver.ts`

1. `test`: Run all tests.

```bash
bun run test
```

2. `test:watch`: Run tests in watch mode.

```bash
bun run test:watch
```

3. `test:bail`: Run tests in watch mode with bail and verbose options.

```bash
bun run test:bail
```

4. `test:log`: Run tests and save logs to a file.

```bash
bun run test:log
```

5. `cli`: Run the CLI tool.

```bash
bun run cli
```

The CLI accepts a `--watcher` option during create and update operations to specify one or more watcher URLs.

6. `build`: Build the package.

```bash
bun run build
```

7. `build:clean`: Clean the build directory.

```bash
bun run build:clean
```

## Releasing

Publishing is **fully automated** and happens **only** when a maintainer publishes a GitHub Release.

- **Who can publish**: GitHub users with **write**, **maintain**, or **admin** permission on this repo.
- **Required tag format**: `vMAJOR.MINOR.PATCH` (for example `v2.7.5`).
- **Required semver bump**: the tag must be a **single** major/minor/patch increment over the latest existing `v*` tag.

### How to cut a release

1. In GitHub, go to **Releases** โ†’ **Draft a new release**
2. Set **Tag** to the next version, e.g. `v2.7.5`
3. Choose the target branch/commit (typically `main`)
4. Click **Publish release**

That will trigger the publish workflow, which will:

- validate the tag + your repo permission
- set `package.json` version from the tag (without the leading `v`)
- run `bun test` and `bun run build`
- publish to npm

### npm authentication

Publishing uses [npm OIDC trusted publishing](https://docs.npmjs.com/trusted-publishers) โ€” the workflow exchanges its GitHub Actions OIDC token for a short-lived npm publish token at publish time. No static `NPM_TOKEN` is required.

For this to work, the `didwebvh-ts` package on npmjs.com must have a Trusted Publisher configured pointing at this repository and the `.github/workflows/publish.yml` workflow.

### Troubleshooting

- **Tag rejected**: make sure it matches `vX.Y.Z` and is exactly one major/minor/patch bump over the latest `v*` tag.
- **Permission rejected**: ensure the releasing user has write/maintain/admin permission on the GitHub repo.
- **`EOTP` / OTP required at publish**: the npm token path is being used instead of OIDC. Make sure no `NODE_AUTH_TOKEN` is set on the publish step and that the workflow has `id-token: write` permission.
- **OIDC exchange failed**: confirm the Trusted Publisher config on npmjs.com matches this repo's owner, name, and workflow file path (`.github/workflows/publish.yml`).

## Creating a DID Resolver

The `didwebvh-ts` library provides the core functionality for resolving DIDs, but it does not include a built-in HTTP resolver. You can create your own resolver using your preferred web framework by following these steps:

1. Import the `resolveDID` function from the `didwebvh-ts` library:

```typescript
import { resolveDID } from 'didwebvh-ts';
```

2. Create endpoints for resolving DIDs:

```typescript
// Example using Express
app.get('/resolve/:id', async (req, res) => {
try {
const result = await resolveDID(req.params.id);
res.json(result);
} catch (error) {
res.status(400).json({
error: 'Resolution failed',
details: error.message
});
}
});
```

3. Implement file retrieval logic for DID documents and associated resources.

For complete examples, see the [examples](./examples/) directory.

### Resolution metadata notes (v1.0)

For `did:webvh:1.0` resolution flows, resolver failures that invalidate the DID are surfaced using:

- `meta.error = "invalidDid"`
- `meta.problemDetails` populated with RFC9457-style fields (`type`, `title`, `detail`)

Absence cases (for example missing DID log or missing DID URL resource) use:

- `meta.error = "notFound"`

When resolving a requested earlier version (for example with `versionId`, `versionNumber`, or `versionTime`), the resolver may return a valid earlier document while still reporting `meta.error = "invalidDid"` if a later log entry fails verification.

## API Reference

### Core Functions

- `resolveDID(did: string, options?: ResolutionOptions): Promise<{did: string, doc: any, meta: DIDResolutionMeta, controlled: boolean}>`
Resolves a DID to its DID document.
For `v1.0`, `options.fastResolve` is an opt-in mode defaulting to `false` for full log parsing.

- `resolveDIDFromLog(log: DIDLog, options?: ResolutionOptions & { witnessProofs?: WitnessProofFileEntry[] }): Promise<{did: string, doc: any, meta: DIDResolutionMeta}>`
Resolves directly from an in-memory DID log.
For `v1.0`, `options.fastResolve` is an opt-in mode defaulting to `false` for full log parsing.

- `createDID(options: CreateDIDInterface): Promise<{did: string, doc: any, meta: DIDResolutionMeta, log: DIDLog, webDoc?: DIDDoc}>`
Creates a new DID.
Accepts `address` (`host`, `host:port`, `https://...`, or `did:webvh:...`) or legacy `domain`.
Resolver URL mapping uses `http://localhost` for local testing and `https://` for non-local hosts.
If `alsoKnownAsWeb: true` is supplied, the result also includes `webDoc`, the parallel `did:web` DID document to publish as `did.json`.

- `updateDID(options: UpdateDIDInterface): Promise<{did: string, doc: any, meta: DIDResolutionMeta, log: DIDLog, webDoc?: DIDDoc}>`
Updates an existing DID.
Returns `webDoc` when the updated DID document carries a `did:web:` alias in `alsoKnownAs`.

- `deactivateDID(options: DeactivateDIDInterface): Promise<{did: string, doc: any, meta: DIDResolutionMeta, log: DIDLog}>`
Deactivates an existing DID.

- `generateParallelDidWeb(didwebvhDid: string, didwebvhDoc: DIDDoc): DIDDoc`
Generates the parallel `did:web` document defined by did:webvh v1.0 ยง3.7.10.

### Witness Functions

- `createWitnessProof(signer, versionId, verificationMethod, created?): Promise`
Creates and signs one witness proof for a specific `versionId`.

- `signWitnessProofEntry(options: WitnessSigningOptions): Promise`
Signs one did-witness proof entry (`{ versionId, proof[] }`) for a single target version.

- `signWitnessProofEntries(versionIds: string[], witnesses: WitnessEntry[], witnessSignersByDid: Record, created?: string): Promise`
Signs did-witness proof entries for multiple target versions.

### Cryptography Functions

- `createDocumentSigner(options: SignerOptions): Signer`
Creates a signer for signing DID documents.

- `prepareDataForSigning(data: any): Uint8Array`
Prepares data for signing.

- `createProof(options: SigningInput): Promise`
Creates a proof for a DID document.

- `createSigner(options: SignerOptions): Signer`
Creates a signer for signing data.

- `AbstractCrypto`
An abstract class for implementing custom signers.

## License

This project is licensed under the [MIT License](LICENSE).