Skip to content

Commit 764fef3

Browse files
authored
Include package name in healthcheck version (#129)
* chore: report the package name in the healthcheck endpoint * Format
1 parent 75a328b commit 764fef3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1292
-638
lines changed

.changeset/twenty-canyons-run.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@getcirrus/pds": patch
3+
---
4+
5+
Include "cirrus" in the version string returned from the health check endpoint.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ If you've cloned to a new machine and see the "Key Recovery Required" error:
9090
### If You've Lost Your Key
9191

9292
**For did:web users:**
93+
9394
- Generate a new key by clearing `.dev.vars` and re-running `pds init`
9495
- Old signatures become unverifiable – followers may see warnings
9596
- Your identity continues, but there's no cryptographic proof of continuity
9697

9798
**For did:plc users:**
99+
98100
- If you have a recovery key registered with PLC, you can rotate to a new signing key
99101
- Without a recovery key, you'll need to start a new identity
100102
- See the [AT Protocol PLC documentation](https://github.com/did-method-plc/did-method-plc) for recovery operations

packages/create-pds/templates/pds-worker/README.md

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pnpm pds init
3737
```
3838

3939
This prompts for:
40+
4041
- **PDS hostname** – The deployment domain (e.g., `pds.example.com`)
4142
- **Handle** – The Bluesky username (e.g., `alice.example.com`)
4243
- **Password** – For logging in from Bluesky apps
@@ -97,6 +98,7 @@ pnpm pds identity
9798
```
9899

99100
This updates your DID document to point to your new PDS. You'll need to:
101+
100102
1. Enter your password for the source PDS
101103
2. Enter the confirmation token sent to your email
102104

@@ -129,47 +131,48 @@ pnpm pds status # Verify everything is working
129131

130132
## CLI Commands
131133

132-
| Command | Description |
133-
|---------|-------------|
134-
| `pnpm pds init` | Interactive setup wizard (prompts for Cloudflare deploy) |
135-
| `pnpm pds migrate` | Transfer account from source PDS |
136-
| `pnpm pds migrate --clean` | Reset and re-import data |
137-
| `pnpm pds identity` | Update DID document to point to new PDS |
138-
| `pnpm pds activate` | Enable writes (go live) |
139-
| `pnpm pds deactivate` | Disable writes (for re-import) |
140-
| `pnpm pds status` | Check account and repository status |
141-
| `pnpm pds passkey add` | Register a passkey for passwordless login |
142-
| `pnpm pds secret key` | Generate new signing keypair |
143-
| `pnpm pds secret jwt` | Generate new JWT secret |
144-
| `pnpm pds secret password` | Set account password |
134+
| Command | Description |
135+
| -------------------------- | -------------------------------------------------------- |
136+
| `pnpm pds init` | Interactive setup wizard (prompts for Cloudflare deploy) |
137+
| `pnpm pds migrate` | Transfer account from source PDS |
138+
| `pnpm pds migrate --clean` | Reset and re-import data |
139+
| `pnpm pds identity` | Update DID document to point to new PDS |
140+
| `pnpm pds activate` | Enable writes (go live) |
141+
| `pnpm pds deactivate` | Disable writes (for re-import) |
142+
| `pnpm pds status` | Check account and repository status |
143+
| `pnpm pds passkey add` | Register a passkey for passwordless login |
144+
| `pnpm pds secret key` | Generate new signing keypair |
145+
| `pnpm pds secret jwt` | Generate new JWT secret |
146+
| `pnpm pds secret password` | Set account password |
145147

146148
Add `--dev` to target your local development server instead of production.
147149

148150
## Configuration
149151

150152
### Public Variables (wrangler.jsonc)
151153

152-
| Variable | Description |
153-
|----------|-------------|
154-
| `PDS_HOSTNAME` | Public hostname (e.g., pds.example.com) |
155-
| `DID` | Account DID |
156-
| `HANDLE` | Account handle |
157-
| `SIGNING_KEY_PUBLIC` | Public key for DID document |
154+
| Variable | Description |
155+
| -------------------- | --------------------------------------- |
156+
| `PDS_HOSTNAME` | Public hostname (e.g., pds.example.com) |
157+
| `DID` | Account DID |
158+
| `HANDLE` | Account handle |
159+
| `SIGNING_KEY_PUBLIC` | Public key for DID document |
158160

159161
### Secrets (.dev.vars or Cloudflare)
160162

161-
| Variable | Description |
162-
|----------|-------------|
163-
| `AUTH_TOKEN` | Bearer token for API write operations |
164-
| `SIGNING_KEY` | Private signing key |
165-
| `JWT_SECRET` | Secret for session tokens |
166-
| `PASSWORD_HASH` | Bcrypt hash of the account password |
163+
| Variable | Description |
164+
| --------------- | ------------------------------------- |
165+
| `AUTH_TOKEN` | Bearer token for API write operations |
166+
| `SIGNING_KEY` | Private signing key |
167+
| `JWT_SECRET` | Secret for session tokens |
168+
| `PASSWORD_HASH` | Bcrypt hash of the account password |
167169

168170
## Handle Verification
169171

170172
Bluesky verifies control of the handle domain.
171173

172174
**If the handle matches the PDS hostname** (for example, both are `pds.example.com`):
175+
173176
- No extra setup needed. The PDS handles verification automatically.
174177

175178
**If the handle is on a different domain** (for example, handle `alice.example.com`, PDS at `pds.example.com`):
@@ -205,12 +208,14 @@ Ensure the worker is deployed (`pnpm run deploy`) or the dev server is running (
205208
### "Failed to resolve handle"
206209

207210
Check the handle configuration:
211+
208212
- For DNS verification: ensure the TXT record has propagated (`dig TXT _atproto.yourhandle.com`)
209213
- For same-domain handles: ensure the PDS is accessible at `https://yourdomain.com/.well-known/atproto-did`
210214

211215
### Migration issues
212216

213217
If migration fails partway through:
218+
214219
- Run `pnpm pds migrate` again to resume from where you left off
215220
- Use `pnpm pds migrate --clean` to start fresh (only on deactivated accounts)
216221

packages/oauth-provider/README.md

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,28 @@ import { OAuthStorage } from "./your-storage-implementation";
2929

3030
// Initialize the provider
3131
const provider = new OAuthProvider({
32-
issuer: "https://your-pds.example.com",
33-
storage: new OAuthStorage(),
32+
issuer: "https://your-pds.example.com",
33+
storage: new OAuthStorage(),
3434
});
3535

3636
// Handle OAuth endpoints in your Worker
3737
app.post("/oauth/par", async (c) => {
38-
const result = await provider.handlePAR(await c.req.formData());
39-
return c.json(result);
38+
const result = await provider.handlePAR(await c.req.formData());
39+
return c.json(result);
4040
});
4141

4242
app.get("/oauth/authorize", async (c) => {
43-
const result = await provider.handleAuthorize(c.req.url);
44-
// Show authorization UI to user
45-
return c.html(renderAuthUI(result));
43+
const result = await provider.handleAuthorize(c.req.url);
44+
// Show authorization UI to user
45+
return c.html(renderAuthUI(result));
4646
});
4747

4848
app.post("/oauth/token", async (c) => {
49-
const result = await provider.handleToken(
50-
await c.req.formData(),
51-
c.req.header("DPoP"),
52-
);
53-
return c.json(result);
49+
const result = await provider.handleToken(
50+
await c.req.formData(),
51+
c.req.header("DPoP"),
52+
);
53+
return c.json(result);
5454
});
5555
```
5656

@@ -72,29 +72,29 @@ The provider uses a storage interface that you implement for your backend:
7272

7373
```typescript
7474
export interface OAuthProviderStorage {
75-
// Authorization codes
76-
saveAuthCode(code: string, data: AuthCodeData): Promise<void>;
77-
getAuthCode(code: string): Promise<AuthCodeData | null>;
78-
deleteAuthCode(code: string): Promise<void>;
79-
80-
// Access/refresh tokens
81-
saveTokens(data: TokenData): Promise<void>;
82-
getTokenByAccess(accessToken: string): Promise<TokenData | null>;
83-
getTokenByRefresh(refreshToken: string): Promise<TokenData | null>;
84-
revokeToken(accessToken: string): Promise<void>;
85-
revokeAllTokens(sub: string): Promise<void>;
86-
87-
// Client metadata cache
88-
saveClient(clientId: string, metadata: ClientMetadata): Promise<void>;
89-
getClient(clientId: string): Promise<ClientMetadata | null>;
90-
91-
// PAR (Pushed Authorization Requests)
92-
savePAR(requestUri: string, data: PARData): Promise<void>;
93-
getPAR(requestUri: string): Promise<PARData | null>;
94-
deletePAR(requestUri: string): Promise<void>;
95-
96-
// DPoP nonce tracking
97-
checkAndSaveNonce(nonce: string): Promise<boolean>;
75+
// Authorization codes
76+
saveAuthCode(code: string, data: AuthCodeData): Promise<void>;
77+
getAuthCode(code: string): Promise<AuthCodeData | null>;
78+
deleteAuthCode(code: string): Promise<void>;
79+
80+
// Access/refresh tokens
81+
saveTokens(data: TokenData): Promise<void>;
82+
getTokenByAccess(accessToken: string): Promise<TokenData | null>;
83+
getTokenByRefresh(refreshToken: string): Promise<TokenData | null>;
84+
revokeToken(accessToken: string): Promise<void>;
85+
revokeAllTokens(sub: string): Promise<void>;
86+
87+
// Client metadata cache
88+
saveClient(clientId: string, metadata: ClientMetadata): Promise<void>;
89+
getClient(clientId: string): Promise<ClientMetadata | null>;
90+
91+
// PAR (Pushed Authorization Requests)
92+
savePAR(requestUri: string, data: PARData): Promise<void>;
93+
getPAR(requestUri: string): Promise<PARData | null>;
94+
deletePAR(requestUri: string): Promise<void>;
95+
96+
// DPoP nonce tracking
97+
checkAndSaveNonce(nonce: string): Promise<boolean>;
9898
}
9999
```
100100

@@ -122,8 +122,8 @@ Response:
122122

123123
```json
124124
{
125-
"request_uri": "urn:ietf:params:oauth:request_uri:XXXXXX",
126-
"expires_in": 90
125+
"request_uri": "urn:ietf:params:oauth:request_uri:XXXXXX",
126+
"expires_in": 90
127127
}
128128
```
129129

@@ -162,12 +162,12 @@ Response:
162162

163163
```json
164164
{
165-
"access_token": "XXXXXX",
166-
"token_type": "DPoP",
167-
"expires_in": 3600,
168-
"refresh_token": "YYYYYY",
169-
"scope": "atproto",
170-
"sub": "did:plc:abc123"
165+
"access_token": "XXXXXX",
166+
"token_type": "DPoP",
167+
"expires_in": 3600,
168+
"refresh_token": "YYYYYY",
169+
"scope": "atproto",
170+
"sub": "did:plc:abc123"
171171
}
172172
```
173173

@@ -202,14 +202,14 @@ Clients are identified by a URL pointing to their metadata document:
202202

203203
```json
204204
{
205-
"client_id": "https://client.example.com/client-metadata.json",
206-
"client_name": "Example App",
207-
"redirect_uris": ["https://client.example.com/callback"],
208-
"grant_types": ["authorization_code", "refresh_token"],
209-
"response_types": ["code"],
210-
"scope": "atproto",
211-
"token_endpoint_auth_method": "none",
212-
"application_type": "web"
205+
"client_id": "https://client.example.com/client-metadata.json",
206+
"client_name": "Example App",
207+
"redirect_uris": ["https://client.example.com/callback"],
208+
"grant_types": ["authorization_code", "refresh_token"],
209+
"response_types": ["code"],
210+
"scope": "atproto",
211+
"token_endpoint_auth_method": "none",
212+
"application_type": "web"
213213
}
214214
```
215215

@@ -224,15 +224,15 @@ This provider is designed to work seamlessly with `@atproto/oauth-client`:
224224
import { OAuthClient } from "@atproto/oauth-client";
225225

226226
const client = new OAuthClient({
227-
clientMetadata: {
228-
client_id: "https://my-app.example.com/client-metadata.json",
229-
redirect_uris: ["https://my-app.example.com/callback"],
230-
},
227+
clientMetadata: {
228+
client_id: "https://my-app.example.com/client-metadata.json",
229+
redirect_uris: ["https://my-app.example.com/callback"],
230+
},
231231
});
232232

233233
// Initiate login
234234
const authUrl = await client.authorize("https://user-pds.example.com", {
235-
scope: "atproto",
235+
scope: "atproto",
236236
});
237237

238238
// Handle callback
@@ -245,8 +245,8 @@ The provider returns standard OAuth 2.1 error responses:
245245

246246
```json
247247
{
248-
"error": "invalid_request",
249-
"error_description": "Missing required parameter: code_challenge"
248+
"error": "invalid_request",
249+
"error_description": "Missing required parameter: code_challenge"
250250
}
251251
```
252252

0 commit comments

Comments
 (0)