TypeScript implementation of the Vana Data Portability Protocol's Personal Server. Stores user data locally, serves it to authorized users via grant-enforced APIs, and syncs encrypted copies to storage backends.
NPM workspaces monorepo with three packages:
| Package | Purpose |
|---|---|
packages/core | Protocol logic — auth, grants, scopes, storage, keys, gateway client |
packages/server | Hono HTTP server — routes, middleware, composition root |
packages/cli | Facade package for external tools (@opendatalabs/personal-server-ts) |
By default, Personal Server uses ~/personal-server as its root namespace:
- Data:
~/personal-server/data/ - Config:
~/personal-server/config.json - Index:
~/personal-server/index.db - Server keypair:
~/personal-server/key.json - Access logs:
~/personal-server/logs/
Override the root with PERSONAL_SERVER_ROOT_PATH (for example, Data Connect can use ~/data-connect/personal-server).
node -v # >= 20 npm install cp .env.example .env # dev/test master key — see file for details npm run buildnpm start # build + start server npm run dev # run from source (no build step) PERSONAL_SERVER_ROOT_PATH=~/data-connect/personal-server npm startThe server starts on the port defined in ${PERSONAL_SERVER_ROOT_PATH:-~/personal-server}/config.json (default: 8080). Health check at GET /health.
The server reads ${PERSONAL_SERVER_ROOT_PATH:-~/personal-server}/config.json on startup (created with defaults if missing).
{ "server": { "port": 8080 }, "logging": { "level": "info", "pretty": false }, "storage": { "backend": "local" } }Set "pretty": true for human-readable logs during development.
Register your server with the Vana Gateway so it can participate in the data portability network:
export VANA_OWNER_PRIVATE_KEY=0x... # your owner wallet private key npm run register-server # uses server.origin from config npm run register-server https://my.server # override server URL PERSONAL_SERVER_ROOT_PATH=~/data-connect/personal-server npm run register-serverThe script signs an EIP-712 ServerRegistration message with the owner key and POSTs it to the gateway. Once registered, GET /health will show delegation.registered: true.
npm test # run all tests npm run test:watch # watch mode npm run test:e2e # end-to-end tests (limited mocking)Tests are co-located with source (foo.ts → foo.test.ts).
All authenticated endpoints use Authorization: Web3Signed <base64url(json)>.<signature> — no sessions, no cookies.
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/health | GET | None | Health check |
/v1/data/{scope} | POST | Owner | Ingest data |
/v1/data | GET | Builder | List scopes |
/v1/data/{scope} | GET | Builder + Grant | Read data |
/v1/data/{scope}/versions | GET | Builder | List versions |
/v1/data/{scope} | DELETE | Owner | Delete data |
/v1/grants | GET | Owner | List grants |
/v1/grants/verify | POST | None | Verify grant signature |
/v1/access-logs | GET | Owner | Access history |
/v1/sync/trigger | POST | Owner | Force sync |
/v1/sync/status | GET | Owner | Sync status |
/v1/sync/file/{fileId} | POST | Owner | Sync specific file |
- DPv1 Protocol Spec — canonical protocol behavior
- Architecture — design decisions and repo structure