pds.js

A single-account AT Protocol Personal Data Server written in JavaScript. Runs on Node.js, Deno, or Cloudflare Workers. Federates with the live network.

Work in progress. Experimental. Probably not production-ready yet, though the author's account, @chadtmiller.com, runs on it.


What makes this different from the official PDS

The official atproto PDS is a multi-tenant server built for running thousands of accounts. pds.js is built around a different premise: one server, one identity, yours.

Labs features (experimental)

Each one is off by default. Configuration has the setting that turns each on. They are exempt from semver and may change shape or disappear in any release, including a patch.


Quick start

$ git clone https://tangled.org/chadtmiller.com/pds.js
$ cd pds.js && pnpm install
$ just dev

The workspace uses the workspace:* protocol, so install with pnpm. just dev needs just and Docker. It starts a local PLC, relay, and Caddy, runs the PDS, and registers a mock account with a few records. Open localhost:2471/account and sign in with the printed credentials. just dev-down tears it all down.

Deploy

The fastest path is start.pdsjs.dev, a browser wizard that deploys to your own Cloudflare account. It generates your signing key and secrets client-side. Nothing sensitive leaves your tab.

For manual deployments:

TargetGuide
Dockerdeploy-docker.md
Node.jsdeploy-node.md
Cloudflare Workersdeploy-cloudflare.md
Denodeploy-deno.md

Every deployment needs TLS in front of it, a public hostname, and one run of npm run setup to register the DID with the PLC directory.


The account interface

Sign in at /account. The PDS serves every page itself, with no external dashboard.

Example apps

Four working apps live in examples/apps/. Each one discovers whose repo it serves from its own origin, so any of them runs on any pds.js account that installs it.

AppWhat it does
photos.mjsPhoto galleries from social.grain.* records. Justified layouts, lightbox, map, terrain headers, network favourite counts
roasts.mjsCoffee roast log with a live timer, weight-loss and development metrics against a Sweet Maria's roast card, notes and photos
drop.mjsImage host. Drag, paste, or pick a file and the public /.blobs/<cid> URL copies itself
videos.mjsVideo gallery from Drive. Plays same-origin with seeking, read-only; uploads happen in Drive
$ pdsjs-site install at://you.example.com/dev.pdsjs.app.manifest/photos

What it implements

pds.js covers the com.atproto.repo.*, com.atproto.sync.*, com.atproto.server.*, and com.atproto.identity.* namespaces. That includes record writes, the firehose over subscribeRepos, streaming blob upload and ranged download, handle resolution and rename, and account migration in and out. It signs commits with a did:plc identity and proxies app.bsky.* to an AppView with service auth.

Sessions come from passwords, app passwords, passkeys, or OAuth 2.0 with PKCE and DPoP-bound tokens.

There are no com.atproto.admin.* endpoints and no invite codes. A single-account server has nobody to administer. The endpoint comparison lists every endpoint on both sides.

Documentation

DocumentContents
ConfigurationEvery environment variable
ArchitecturePorts, adapters, packages, library usage
Building an appSites, manifests, installs, how to update
Permissioned dataSpaces proposal, the run club example
Endpoint comparisonCoverage against the official atproto PDS
Scope comparisonOAuth scopes against the reference implementation
ContributingLocal dev setup, tests, commit gate

Served by pds.js Runs on atproto Best viewed with any browser

Source at tangled.org/chadtmiller.com/pds.js. Packages on npm under @pdsjs. MIT licensed.

This page is a record in an atproto repo, served by the pds.js instance that holds it. The mark follows the unofficial JavaScript logo by Chris Williams, which is public domain.

connecting to pds.pdsjs.dev