@ascorbic/pds 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # @ascorbic/pds
2
+
3
+ A single-user [AT Protocol](https://atproto.com) Personal Data Server (PDS) that runs on Cloudflare Workers. Host your own Bluesky identity with minimal infrastructure.
4
+
5
+ > **⚠️ Experimental Software**
6
+ >
7
+ > 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.
8
+
9
+ ## What is this?
10
+
11
+ A PDS is where your Bluesky data lives - your posts, follows, profile, and media. This package lets you run your own PDS on Cloudflare's edge network, giving you:
12
+
13
+ - **Your own identity** - Use your own domain as your Bluesky handle
14
+ - **Data ownership** - Your content lives in your Cloudflare account
15
+ - **Federation** - Works with the Bluesky network via relay sync
16
+ - **Low cost** - Runs on Cloudflare's generous free tier
17
+
18
+ ## Quick Start
19
+
20
+ The fastest way to get started:
21
+
22
+ ```bash
23
+ npm create pds
24
+ ```
25
+
26
+ This scaffolds a new project, installs dependencies, and runs the setup wizard to configure your PDS.
27
+
28
+ Then start the dev server:
29
+
30
+ ```bash
31
+ cd pds-worker
32
+ npm run dev
33
+ ```
34
+
35
+ ## Manual Installation
36
+
37
+ If you prefer to set things up yourself:
38
+
39
+ ### 1. Install the package
40
+
41
+ ```bash
42
+ npm install @ascorbic/pds
43
+ ```
44
+
45
+ ### 2. Create a worker entry point
46
+
47
+ ```typescript
48
+ // src/index.ts
49
+ export { default, AccountDurableObject } from "@ascorbic/pds";
50
+ ```
51
+
52
+ ### 3. Configure wrangler.jsonc
53
+
54
+ ```jsonc
55
+ {
56
+ "name": "my-pds",
57
+ "main": "src/index.ts",
58
+ "compatibility_date": "2024-12-01",
59
+ "compatibility_flags": ["nodejs_compat"],
60
+ "durable_objects": {
61
+ "bindings": [{ "name": "ACCOUNT", "class_name": "AccountDurableObject" }],
62
+ },
63
+ "migrations": [
64
+ { "tag": "v1", "new_sqlite_classes": ["AccountDurableObject"] },
65
+ ],
66
+ "r2_buckets": [{ "binding": "BLOBS", "bucket_name": "pds-blobs" }],
67
+ }
68
+ ```
69
+
70
+ ### 4. Run the setup wizard
71
+
72
+ ```bash
73
+ pnpm pds init
74
+ ```
75
+
76
+ This prompts for your hostname, handle, and password, then generates signing keys and writes configuration.
77
+
78
+ ## CLI
79
+
80
+ The package includes a CLI for setup and configuration:
81
+
82
+ ```bash
83
+ pds init # Interactive setup (writes to .dev.vars)
84
+ pds init --production # Deploy secrets to Cloudflare
85
+ pds secret key # Generate new signing keypair
86
+ pds secret jwt # Generate new JWT secret
87
+ pds secret password # Set account password
88
+ ```
89
+
90
+ ## Deploying to Production
91
+
92
+ 1. [Enable R2 in your Cloudflare dashboard](https://dash.cloudflare.com/?to=/:account/r2/overview) (the bucket will be created automatically on first deploy).
93
+
94
+ 2. Run the production setup to deploy secrets:
95
+
96
+ ```bash
97
+ npx pds init --production
98
+ ```
99
+
100
+ 3. Deploy your worker:
101
+
102
+ ```bash
103
+ wrangler deploy
104
+ ```
105
+
106
+ 4. Configure DNS to point your domain to the worker.
107
+
108
+ ## Identity: DIDs and Handles
109
+
110
+ AT Protocol uses two types of identifiers:
111
+
112
+ - **DID** (Decentralized Identifier): Your permanent, cryptographic identity (e.g., `did:web:pds.example.com`). This never changes and is tied to your signing key.
113
+ - **Handle**: Your human-readable username (e.g., `alice.example.com`). This can be any domain you control.
114
+
115
+ 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.
116
+
117
+ ### Handle Verification
118
+
119
+ Bluesky verifies that you control your handle domain. There are two methods:
120
+
121
+ #### Option A: Handle matches PDS hostname
122
+
123
+ If your handle is the same as your PDS hostname (e.g., both are `pds.example.com`):
124
+
125
+ - The PDS automatically serves `/.well-known/atproto-did` returning your DID
126
+ - No additional DNS setup needed
127
+ - This is the simplest option
128
+
129
+ #### Option B: Handle on a different domain
130
+
131
+ If you want a handle on a different domain (e.g., handle `alice.example.com` while PDS is at `pds.example.com`):
132
+
133
+ 1. Add a DNS TXT record to your handle domain:
134
+
135
+ ```
136
+ _atproto.alice.example.com TXT "did=did:web:pds.example.com"
137
+ ```
138
+
139
+ 2. Verify it's working:
140
+
141
+ ```bash
142
+ dig TXT _atproto.alice.example.com
143
+ ```
144
+
145
+ This lets you use any domain you own as your Bluesky handle, even your personal website.
146
+
147
+ ## Configuration
148
+
149
+ 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.
150
+
151
+ ### Public Variables (wrangler.jsonc)
152
+
153
+ | Variable | Description |
154
+ | -------------------- | ---------------------------------------- |
155
+ | `PDS_HOSTNAME` | Public hostname (e.g., pds.example.com) |
156
+ | `DID` | Account DID (did:web:... or did:plc:...) |
157
+ | `HANDLE` | Account handle |
158
+ | `SIGNING_KEY_PUBLIC` | Public key for DID document (multibase) |
159
+
160
+ ### Secrets
161
+
162
+ | Variable | Description |
163
+ | --------------- | ------------------------------------- |
164
+ | `AUTH_TOKEN` | Bearer token for API write operations |
165
+ | `SIGNING_KEY` | Private signing key (secp256k1 JWK) |
166
+ | `JWT_SECRET` | Secret for signing session JWTs |
167
+ | `PASSWORD_HASH` | Bcrypt hash of password for app login |
168
+
169
+ ## API Endpoints
170
+
171
+ ### Public
172
+
173
+ | Endpoint | Description |
174
+ | ------------------------------------------- | ---------------------------- |
175
+ | `GET /.well-known/did.json` | DID document |
176
+ | `GET /.well-known/atproto-did` | Handle verification |
177
+ | `GET /xrpc/com.atproto.sync.getRepo` | Export repository as CAR |
178
+ | `GET /xrpc/com.atproto.sync.subscribeRepos` | WebSocket firehose |
179
+ | `GET /xrpc/com.atproto.repo.describeRepo` | Repository metadata |
180
+ | `GET /xrpc/com.atproto.repo.getRecord` | Get a single record |
181
+ | `GET /xrpc/com.atproto.repo.listRecords` | List records in a collection |
182
+
183
+ ### Authenticated
184
+
185
+ | Endpoint | Description |
186
+ | ---------------------------------------------- | -------------------------- |
187
+ | `POST /xrpc/com.atproto.server.createSession` | Login (returns JWT) |
188
+ | `POST /xrpc/com.atproto.server.refreshSession` | Refresh JWT |
189
+ | `POST /xrpc/com.atproto.repo.createRecord` | Create a record |
190
+ | `POST /xrpc/com.atproto.repo.deleteRecord` | Delete a record |
191
+ | `POST /xrpc/com.atproto.repo.putRecord` | Create or update a record |
192
+ | `POST /xrpc/com.atproto.repo.uploadBlob` | Upload a blob |
193
+ | `POST /xrpc/com.atproto.repo.importRepo` | Import repository from CAR |
194
+
195
+ ## Architecture
196
+
197
+ The PDS runs as a Cloudflare Worker with a Durable Object for state:
198
+
199
+ - **Worker**: Handles routing, authentication, and DID document serving
200
+ - **AccountDurableObject**: Stores repository data in SQLite, manages the Merkle tree
201
+ - **R2**: Stores blobs (images, videos)
202
+
203
+ ## Limitations
204
+
205
+ - **Single-user only**: One account per deployment
206
+ - **No account creation**: The owner is configured at deploy time
207
+ - **did:web only**: Uses domain-based DIDs (did:plc support planned)
208
+
209
+ ## Resources
210
+
211
+ - [AT Protocol Documentation](https://atproto.com)
212
+ - [Bluesky](https://bsky.app)
213
+ - [Cloudflare Workers](https://developers.cloudflare.com/workers/)