
Research
Node.js Fixes AsyncLocalStorage Crash Bug That Could Take Down Production Servers
Node.js patched a crash bug where AsyncLocalStorage could cause stack overflows to bypass error handlers and terminate production servers.
@ascorbic/pds
Advanced tools
A single-user AT Protocol Personal Data Server (PDS) that runs on Cloudflare Workers. Host your own Bluesky identity with minimal infrastructure.
⚠️ Experimental Software
This is an early-stage project under active development. Do not migrate your main Bluesky account to this PDS yet. Use a test account or create a new identity for experimentation. Data loss, breaking changes, and missing features are expected.
A PDS is where your Bluesky data lives – your posts, follows, profile, and media. This package lets you run your own PDS on Cloudflare Workers, giving you control over your data and identity.
The fastest way to get started:
npm create pds
This scaffolds a new project, installs dependencies, and runs the setup wizard to configure your PDS.
Then start the dev server:
cd pds-worker
npm run dev
If you prefer to set things up yourself:
npm install @ascorbic/pds
// src/index.ts
export { default, AccountDurableObject } from "@ascorbic/pds";
{
"name": "my-pds",
"main": "src/index.ts",
"compatibility_date": "2024-12-01",
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "ACCOUNT", "class_name": "AccountDurableObject" }],
},
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["AccountDurableObject"] },
],
"r2_buckets": [{ "binding": "BLOBS", "bucket_name": "pds-blobs" }],
}
pnpm pds init
This prompts for your hostname, handle, and password, then generates signing keys and writes configuration.
The package includes a CLI for setup and configuration:
pds init # Interactive setup (writes to .dev.vars)
pds init --production # Deploy secrets to Cloudflare
pds secret key # Generate new signing keypair
pds secret jwt # Generate new JWT secret
pds secret password # Set account password
Enable R2 in your Cloudflare dashboard (the bucket will be created automatically on first deploy).
Run the production setup to deploy secrets:
npx pds init --production
wrangler deploy
AT Protocol uses two types of identifiers:
did:web:pds.example.com). This never changes and is tied to your signing key.alice.example.com). This can be any domain you control.The DID document (served at /.well-known/did.json) contains your public key and tells the network where your PDS is. The alsoKnownAs field links your DID to your handle.
Bluesky verifies that you control your handle domain. There are two methods:
If your handle is the same as your PDS hostname (e.g., both are pds.example.com):
/.well-known/atproto-did returning your DIDIf you want a handle on a different domain (e.g., handle alice.example.com while PDS is at pds.example.com):
_atproto.alice.example.com TXT "did=did:web:pds.example.com"
dig TXT _atproto.alice.example.com
This lets you use any domain you own as your Bluesky handle, even your personal website.
The PDS uses environment variables for configuration. Public values go in wrangler.jsonc, secrets are stored via Wrangler or in .dev.vars for local development.
| Variable | Description |
|---|---|
PDS_HOSTNAME | Public hostname (e.g., pds.example.com) |
DID | Account DID (did:web:... or did:plc:...) |
HANDLE | Account handle |
SIGNING_KEY_PUBLIC | Public key for DID document (multibase) |
| Variable | Description |
|---|---|
AUTH_TOKEN | Bearer token for API write operations |
SIGNING_KEY | Private signing key (secp256k1 JWK) |
JWT_SECRET | Secret for signing session JWTs |
PASSWORD_HASH | Bcrypt hash of password for app login |
| Endpoint | Description |
|---|---|
GET /.well-known/did.json | DID document |
GET /.well-known/atproto-did | Handle verification |
GET /xrpc/com.atproto.sync.getRepo | Export repository as CAR |
GET /xrpc/com.atproto.sync.subscribeRepos | WebSocket firehose |
GET /xrpc/com.atproto.repo.describeRepo | Repository metadata |
GET /xrpc/com.atproto.repo.getRecord | Get a single record |
GET /xrpc/com.atproto.repo.listRecords | List records in a collection |
| Endpoint | Description |
|---|---|
POST /xrpc/com.atproto.server.createSession | Login (returns JWT) |
POST /xrpc/com.atproto.server.refreshSession | Refresh JWT |
POST /xrpc/com.atproto.repo.createRecord | Create a record |
POST /xrpc/com.atproto.repo.deleteRecord | Delete a record |
POST /xrpc/com.atproto.repo.putRecord | Create or update a record |
POST /xrpc/com.atproto.repo.uploadBlob | Upload a blob |
POST /xrpc/com.atproto.repo.importRepo | Import repository from CAR |
The PDS runs as a Cloudflare Worker with a Durable Object for state:
FAQs
AT Protocol PDS on Cloudflare Workers
The npm package @ascorbic/pds receives a total of 24 weekly downloads. As such, @ascorbic/pds popularity was classified as not popular.
We found that @ascorbic/pds demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Node.js patched a crash bug where AsyncLocalStorage could cause stack overflows to bypass error handlers and terminate production servers.

Research
/Security News
A malicious Chrome extension steals newly created MEXC API keys, exfiltrates them to Telegram, and enables full account takeover with trading and withdrawal rights.

Security News
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.