Skip to content

Releases: ascorbic/cirrus

@getcirrus/pds@0.15.1

12 May 13:48
c30eb0b

Choose a tag to compare

Patch Changes

  • #157 241a5fc Thanks @NuroDev! - fix(pds): Remove empty collections from cache on record delete.

    When all records of a collection are deleted, it is now ensured that the collection is deleted from the user repository so collections don't linger around forever

@getcirrus/pds@0.15.0

10 May 15:39
be0a564

Choose a tag to compare

Minor Changes

  • #160 a492bf7 Thanks @ascorbic! - Lexicon validation now matches the reference PDS more closely:
    • createRecord, putRecord, and applyWrites honor the validate flag from the request body. true requires a known schema, false skips schema validation, undefined validates known schemas optimistically.
    • Responses include validationStatus ("valid" for known, "unknown" for unknown collections; omitted when validate: false). Per-write validationStatus is returned in applyWrites results.
    • The record's $type is filled in from collection when missing and rejected on mismatch.
    • Generic record-key shape (isRecordKey) is enforced for any provided rkey, regardless of validate flag — closes a hole where empty-string and path-traversal-style rkeys could reach the repo.
    • Schema-specific record keys are validated against the schema's keySchema for known collections (e.g. app.bsky.feed.post requires a TID, app.bsky.actor.profile requires self).
    • Legacy { cid, mimeType } blob refs are rejected.
    • Bundled schema set broadened to include com.atproto.lexicon.schema, app.bsky.actor.status, app.bsky.notification.declaration, and chat.bsky.actor.declaration.
    • The Durable Object is now the authoritative rkey allocator: when the client doesn't supply an rkey, the worker validates against a candidate (so restrictive keySchemas still reject early) and the DO picks the final rkey against its MST state, with a small retry loop to defeat any worker-isolate clockid collisions.
    • Client-supplied rkey collisions return 409 RecordAlreadyExists instead of a generic 500.
    • Intra-batch duplicate rkeys in applyWrites return 400 InvalidRequest (distinguished from the 409 above).
    • Missing rkey for applyWrites#update/#delete returns 400 InvalidRequest.
    • Non-boolean validate flag values return 400 InvalidRequest.
    • Non-string rkey values (including null) return 400 InvalidRequest.

Patch Changes

  • #162 5920074 Thanks @ascorbic! - Fix relay desync after a failed write (e.g. an image post that errors mid-flight).

    applyWrites was assigning the new Repo to in-memory state before sequencing the firehose event. If anything threw between then and sequenceCommit succeeding, Cloudflare rolled back the SQLite writes but the in-memory Repo stayed advanced. The next successful write then emitted a firehose commit whose since rev the relay had never seen, and the relay marked the repo desynced — requiring a manual requestCrawl to recover.

    this.repo is now only assigned after the sequence + broadcast succeed, and any failure in that window invalidates the in-memory cache so the next access reloads from storage.

@getcirrus/pds@0.14.0

04 May 22:25
5eb1b6b

Choose a tag to compare

Minor Changes

  • #158 ec935b1 Thanks @ascorbic! - Support granular OAuth permissions and permission sets per the atproto permission spec.

    • repo:, rpc:, blob:, account:, identity: scopes are parsed and enforced (via @atproto/oauth-scopes); transition:generic / transition:email / transition:chat.bsky keep working through the transitional shim.
    • verifyAccessToken now accepts a (perms) => p.assertRepo({ collection, action })-style check callback in addition to the legacy required-scope string.
    • PDS write endpoints (createRecord, putRecord, deleteRecord, applyWrites, uploadBlob) assert the matching scope before dispatching.
    • include:NSID?aud=... permission-set scopes are resolved via @atcute/lexicon-resolver and expanded inline at code-issuance time, so resource-server checks never need network access. The PDS caches resolved permission sets in DO SQLite with the spec's stale-while-revalidate semantics (24h soft / 90d hard).
    • The consent UI groups long granular-scope lists by NSID authority and collapses them behind a <details> disclosure, so a 30-scope client like tangled.org renders as a few audit-friendly lines instead of a wall of text. include: scopes render the resolved bundle's title/detail.

    Note on legacy auth: session JWTs (from createSession / app-password flow), service JWTs, and the static AUTH_TOKEN continue to bypass scope checks at resource handlers — they're treated as fully-trusted callers per their original semantics (app-password equivalents). The new rpc: proxy enforcement only applies to OAuth (DPoP) tokens; legacy clients can still call any AppView method via the proxy regardless of granular scopes.

Patch Changes

  • #153 6e4d81d Thanks @georgemblack! - Fix com.atproto.server.checkAccountStatus response to be lexicon-compliant: privateStateValues is a required integer (not nullable), so return 0 instead of null in both the activated and not-activated branches.

  • #155 d1a7074 Thanks @a-lavis! - Fix two OAuth token refresh bugs that prevented spec-compliant clients (e.g. tangled.org via indigo) from refreshing their session after the access token expired.

    • Track access and refresh expiry separately on TokenData (accessExpiresAt / refreshExpiresAt) instead of a single expiresAt. cleanup() now prunes by refreshExpiresAt, so a row isn't deleted while its refresh token is still valid. The PDS SQLite store migrates legacy oauth_tokens rows in place, deriving refresh_expires_at as MAX(expires_at, issued_at + REFRESH_TOKEN_TTL).
    • The PDS auth middleware now sends WWW-Authenticate: DPoP error="invalid_token" on 401 responses for invalid/expired OAuth access tokens, as required by the atproto XRPC spec. Clients that gate refresh on this header (indigo, and others) will now refresh automatically instead of staying logged-in-but-broken until the user signs out.
  • Updated dependencies [ec935b1, d1a7074]:

    • @getcirrus/oauth-provider@0.4.0

@getcirrus/oauth-provider@0.4.0

04 May 22:25
5eb1b6b

Choose a tag to compare

Minor Changes

  • #158 ec935b1 Thanks @ascorbic! - Support granular OAuth permissions and permission sets per the atproto permission spec.

    • repo:, rpc:, blob:, account:, identity: scopes are parsed and enforced (via @atproto/oauth-scopes); transition:generic / transition:email / transition:chat.bsky keep working through the transitional shim.
    • verifyAccessToken now accepts a (perms) => p.assertRepo({ collection, action })-style check callback in addition to the legacy required-scope string.
    • PDS write endpoints (createRecord, putRecord, deleteRecord, applyWrites, uploadBlob) assert the matching scope before dispatching.
    • include:NSID?aud=... permission-set scopes are resolved via @atcute/lexicon-resolver and expanded inline at code-issuance time, so resource-server checks never need network access. The PDS caches resolved permission sets in DO SQLite with the spec's stale-while-revalidate semantics (24h soft / 90d hard).
    • The consent UI groups long granular-scope lists by NSID authority and collapses them behind a <details> disclosure, so a 30-scope client like tangled.org renders as a few audit-friendly lines instead of a wall of text. include: scopes render the resolved bundle's title/detail.

    Note on legacy auth: session JWTs (from createSession / app-password flow), service JWTs, and the static AUTH_TOKEN continue to bypass scope checks at resource handlers — they're treated as fully-trusted callers per their original semantics (app-password equivalents). The new rpc: proxy enforcement only applies to OAuth (DPoP) tokens; legacy clients can still call any AppView method via the proxy regardless of granular scopes.

Patch Changes

  • #155 d1a7074 Thanks @a-lavis! - Fix two OAuth token refresh bugs that prevented spec-compliant clients (e.g. tangled.org via indigo) from refreshing their session after the access token expired.
    • Track access and refresh expiry separately on TokenData (accessExpiresAt / refreshExpiresAt) instead of a single expiresAt. cleanup() now prunes by refreshExpiresAt, so a row isn't deleted while its refresh token is still valid. The PDS SQLite store migrates legacy oauth_tokens rows in place, deriving refresh_expires_at as MAX(expires_at, issued_at + REFRESH_TOKEN_TTL).
    • The PDS auth middleware now sends WWW-Authenticate: DPoP error="invalid_token" on 401 responses for invalid/expired OAuth access tokens, as required by the atproto XRPC spec. Clients that gate refresh on this header (indigo, and others) will now refresh automatically instead of staying logged-in-but-broken until the user signs out.

@getcirrus/pds@0.13.0

30 Mar 06:10
98aec98

Choose a tag to compare

Minor Changes

  • #147 2f06391 Thanks @ascorbic! - Add app password support for AT Protocol client authentication. Implements com.atproto.server.createAppPassword, listAppPasswords, revokeAppPassword, and login via app passwords. Includes CLI commands for creating, listing, and revoking app passwords.

create-pds@0.0.12

21 Mar 14:28
304788d

Choose a tag to compare

Patch Changes

@getcirrus/pds@0.12.0

21 Mar 14:27
304788d

Choose a tag to compare

Minor Changes

@getcirrus/pds@0.11.0

15 Mar 22:06
15487a7

Choose a tag to compare

Minor Changes

  • #137 90e9771 Thanks @ascorbic! - Add option to auto-generate a password during pds init and pds secret password, with clipboard copy support

  • #136 287c971 Thanks @ascorbic! - Add live terminal dashboard for PDS monitoring via pds dashboard. Shows repository stats, federation sync status, firehose subscribers with IPs, real-time event log, and notifications. Also adds a web dashboard at /status.

@getcirrus/pds@0.10.6

14 Mar 19:57
dd9ad5e

Choose a tag to compare

Patch Changes

  • #134 127f3db Thanks @ascorbic! - Fix OAuth client metadata caching to avoid redundant network requests

    Client metadata was re-fetched from the network on every OAuth request instead of using the cache, adding latency to token exchanges and making auth fragile when client metadata endpoints are slow or unavailable.

  • Updated dependencies [e76f1e4, 127f3db]:

    • @getcirrus/oauth-provider@0.3.2

@getcirrus/oauth-provider@0.3.2

14 Mar 19:57
dd9ad5e

Choose a tag to compare

Patch Changes

  • #132 e76f1e4 Thanks @ascorbic! - Fix OAuth client authentication failures for public clients and mixed JWKS

    • Fix invalid_client error for clients that omit token_endpoint_auth_method in their metadata (Zod default of client_secret_basic was passed through unsupported)
    • Fix invalid usage "encrypt" error when client JWKS contains both signing and encryption keys by using jose's createLocalJWKSet for proper key selection
  • #134 127f3db Thanks @ascorbic! - Fix OAuth authentication failure for confidential clients whose JWKS contains invalid key_ops

    Clients with ECDSA signing keys that incorrectly declare encryption operations (e.g. "encrypt", "wrapKey") in their JWKS key_ops field would fail with "invalid usage" during token exchange.