enbox
A decentralised identity wallet for managing DIDs, profiles, protocols, and permissions on the Enbox network.
Live Demo • Blue Variant • Getting Started • Testing • Architecture
Warning
This software is experimental and under active development. It has not been independently audited for security. The cryptographic primitives and key management are provided by the underlying @enbox/* SDK, which is also pre-release. Do not use this wallet to manage sensitive or high-value credentials in production. APIs, storage formats, and recovery mechanisms may change without notice between versions.
- Identity Management -- Create, edit, delete, import, and export decentralised identities (DID:DHT) with auto-generated avatars, banners, and friendly names
- Profile -- Display name, tagline, bio, avatar, and hero images stored on your personal DWN
- App Connect -- Scan QR codes to connect with Enbox-compatible applications
- Permission Control -- View and revoke permission grants from connected apps
- DID Search -- Look up any DID to view its public profile, with recent search history
- Seed Phrase Recovery -- Restore wallet vault from BIP-39 recovery phrase
- Identity Export/Import -- Portable JSON backup and restore of full identity data with export timestamps
- Responsive -- Desktop sidebar + native-feeling mobile bottom tab bar with safe area support
- Themes -- Dark and light modes with build-time product theme variants
- PWA -- Installable with offline service worker support
- Security -- PIN-locked vault, configurable auto-lock (5m / 10m / 30m / 1h / never), session persistence across tab refresh
| Layer | Technology |
|---|---|
| UI | Tailwind CSS v4 + @enbox/ui design tokens |
| Framework | React 18 + TypeScript 5 |
| Client State | Zustand 5 |
| Server State | TanStack Query v5 |
| Routing | React Router v7 |
| Build | Vite 6 |
| Unit Testing | Vitest + Testing Library |
| E2E Testing | Playwright + axe-core |
| CI/CD | GitHub Actions + Codecov |
| Deployment | Cloudflare Pages |
| SDK | @enbox/agent @enbox/api @enbox/auth @enbox/protocols |
# Prerequisites: Bun (https://bun.sh)
# Install dependencies
bun install
# Start dev server (http://localhost:5173)
bun run dev
# Run unit tests
bun run test
# Run unit tests with coverage
bun run test:coverage
# Run E2E tests (requires Chromium)
npx playwright install chromium
bun run test:e2e
# Lint + type check
bun run lint
npx tsc --noEmit
# Production build
bun run buildThe wallet uses a comprehensive testing pyramid:
/\
/ \ E2E — Playwright + real Chromium
/ 26 \ Real browser, real CSS, accessibility audits
/------\
/ \
/ 419 \ Unit/Integration — Vitest + Testing Library
/ \ Components, hooks, stores, user flows
/______________\
Run with Vitest + happy-dom + Testing Library:
- Pure logic: identity generators, protocol names, constants, query keys
- UI components: Button, Dialog, Tabs, PinInput, Avatar, Card, etc.
- User flows: identity list filtering, tab navigation, backup confirmation
- Stores: auth, UI, backup seed, drag-drop state transitions
- Best practices enforced via eslint-plugin-testing-library
bun run test # Run once
bun run test:watch # Watch mode
bun run test:coverage # With v8 coverage reportRun with Playwright in real Chromium at desktop and mobile viewports:
- Setup flow: PIN creation, confirmation, mismatch rejection, keyboard capture
- Accessibility: axe-core WCAG 2.0/2.1 AA audits at both viewports
- Responsive: Desktop (1280px) and mobile (375px) smoke tests
- Screenshots: Captured automatically on failure
npx playwright install chromium # First time only
bun run test:e2e # Run all
npx playwright test --ui # Interactive modeCoverage is enforced in CI via thresholds and reported as PR comments via vitest-coverage-report-action:
| Metric | Threshold | Current |
|---|---|---|
| Statements | 25% | ~26% |
| Branches | 29% | ~31% |
| Functions | 30% | ~32% |
| Lines | 25% | ~27% |
src/
app.css # Tailwind v4 + @enbox/ui design tokens (dark + light)
App.tsx # Auth gate + routing + provider hierarchy
main.tsx # Entry point + PWA service worker
routes.tsx # Lazy-loaded route definitions
test-utils.tsx # Test rendering helpers (renderWithProviders)
components/
ui/ # Shared primitives (Button, Dialog, Tabs, Card, etc.)
identity/ # Identity card, avatar, public card
layout/ # AppShell, Sidebar, BottomNav, AppBar, OfflineBanner
features/
auth/ # Unlock, setup, restore, onboarding identity step
identities/ # List, create, edit, import, details + 5 tabs
connect/ # App Connect (QR scanner), DWeb Connect (popup)
search/ # DID lookup with search history
settings/ # Security, backup, settings hub
enbox/ # SDK integration (designed for @enbox/react extraction)
provider.tsx # EnboxAuthProvider (AuthManager lifecycle + sync)
hooks/ # useAuth, useIdentities, useProfile, usePermissions
queries/ # TanStack Query functions + key factories
mutations/ # Identity CRUD mutations
protocols.ts # Protocol installation (dependency-ordered)
registration.ts # DWN tenant registration
stores/ # Zustand (auth, UI, backup seed, drag-drop)
lib/ # Pure utilities (identity generators, protocol names)
__mocks__/ # Test mock factories (identities, profiles, agents)
e2e/ # Playwright E2E + accessibility specs
| Type | Tool | Examples |
|---|---|---|
| Client state | Zustand | Auth status, UI preferences, sidebar state |
| Server/DWN state | TanStack Query | Identities, profiles, protocols, permissions |
| URL state | React Router v7 | Current page, identity DID params |
The src/enbox/ directory is designed for future extraction into @enbox/react. It has zero imports from UI components or feature pages. All Enbox SDK interactions go through this layer:
App.tsx
└─ EnboxAuthProvider ← manages AuthManager lifecycle
└─ useAuth() ← connect / unlock / restore / lock
└─ useIdentities() ← TanStack Query → agent.identity.list()
└─ useProfile(did) ← TanStack Query → ProfileProtocol
└─ usePermissions(did) ← TanStack Query → DwnApi.permissions
The wallet lets the SDK manage sync automatically. Manual sync intervention only happens during seed phrase restore (controlled two-pull pattern to recover identity metadata then profile data).
Build-time product themes via VITE_PRODUCT_THEME:
| Variant | Accent | Demo |
|---|---|---|
| Default | Rose / Pink | enbox-wallet.pages.dev |
| Blue | Blue | blue-enbox-wallet.pages.dev |
VITE_PRODUCT_THEME=blue bun run buildEvery push triggers:
- Lint -- ESLint + testing-library plugin
- Typecheck --
tsc --noEmit - Unit tests -- Vitest with v8 coverage (PR comments with per-file breakdown)
- E2E tests -- Playwright in real Chromium (with failure screenshots)
- Build -- Vite production build
- Deploy -- Cloudflare Pages (main branch only, both theme variants)
| Secret | Description |
|---|---|
CLOUDFLARE_API_TOKEN |
Cloudflare API token with Pages:Edit |
CLOUDFLARE_ACCOUNT_ID |
Cloudflare account ID |
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run tests (
bun run test && bun run test:e2e) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
All PRs must pass CI (lint + typecheck + unit tests + E2E tests + build).
See LICENSE.