atproto_core
Core library for clients and tools. This package is mainly used by https://atprotodart.com packages.
2.4.1
5.5K downloads/mo
#3708 most downloaded on pub.dev
myConsciousness/atproto.dart
What this package is like to depend on
Last release 15 days ago
08 Aug 2026
Release timing varies
gaps range from 9 days to 7 months
Nearly every release is documented
notes for 86 of 86 stable releases
Nothing withdrawn
no release was ever pulled
3 years old
93 releases · first in 2023
13 releases in the last 12 months
see the full history below
Release timeline
93 releases · Mar 2023 to Aug 2026Releases
latest 60 of 93-
2.4.108 Aug 2026 -
2.4.026 Jul 2026Release notes
Open source →- fix:
decodeCarvalidates the CAR header length instead of trusting it. A truncated archive whose header varint claimed more bytes than exist pushed the cursor past the end and decoded to an EMPTY map — a truncated repository export looked like an empty repository, silently losing every block. It now throwsCarException, the same contract the block-length check already honored. - fix: a varint whose payload reaches the 64th bit no longer wraps to a negative length and escapes as a raw
RangeErrorfrom deep inside the decoder; it is rejected as aCarExceptionin the varint reader itself, so every caller of it is covered. Length checks are also written as subtractions so a near-maximum length cannot overflow the cursor past its own bounds check. - feat: added
ServiceContext.withAdditionalHeaders, which derives a context from this one's headers plus the given ones instead of replacing them.withHeadersreplaces, so every caller adding a single header spread the origin's headers back in by hand — and a spread is key-exact, which leaves a caller'sAtproto-Proxysitting next to the addedatproto-proxy. Header names are case-insensitive, so this merges case-insensitively and the added header wins. - fix:
ServiceContext.headersno longer hands out the context's live internal map. Any holder could write to it, and because a context derived viawithHeadersand the clients built on it read the same field, oneheaders['atproto-proxy'] = ...retargeted every request every one of them made — whileheaders.remove(...)silently dropped a header a client needs for the rest of its life. The map is now copied at construction and exposed unmodifiable, consistently: previously the same write threwUnsupportedErrorwhen no headers had been supplied and succeeded when they had. - fix: a
5xxnow reaches a customRetryStrategywith its true status code.checkStatusfunnels500,502,503and504into a singleInternalServerErrorException, and the retry layer hardcodedstatusCode: 500when building theRetryContext, so a strategy branching oncontext.statusCode == 503could never match. - fix: a
Retry-After/ratelimit-resetsent with a server error is now honored. It was read only on the429path, so the wait a503asked for was silently dropped. - fix: a
401provoked by an access token the session has already rotated past no longer triggers a further refresh. Single-flighting only coalesces requests that overlap an in-progress refresh; a request already on the wire with the superseded token 401s after the rotation lands, and each such response used to chain another rotation — spending an unused refresh token and emitting anonSessionUpdatedthe owner has to persist. The token the failed request actually carried is now compared against the current session, and a stale one is simply retried. - fix: the exponential backoff in
RetryConfigis now capped at 60 seconds, matching the "capped exponential backoff" it documents. Uncapped,2 ^ (attempt - 1)reaches roughly six days by attempt 20. - fix: a server-requested wait can no longer shorten a retry. The 60-second clamp was applied after the comparison, so a server asking for 1000s while the backoff stood at 512s collapsed the wait to 60s — a larger requested delay produced a shorter wait than plain backoff.
- fix: a user-supplied
onRefreshSessionis now bounded by the context'stimeout. It is awaited at the head of every request behind a single flight, so one that never completed stalled every request on the context forever;timeoutpreviously covered only the xrpc call. - fix:
Challenge.executeno longer exposes its recursion state (attempt,dpopNonceRetryCount,sessionRefreshed) on the public signature, where a caller passing e.g.attempt: 5corrupted the retry accounting.Challengeis publicly exported; the loop state moved to a private_execute. - docs:
RetryConfigdocumented its jitter as0 ~ 3while the implementation drew0 ~ 4inclusive.
- fix:
-
2.3.026 Jul 2026Release notes
Open source →- feat: added
ServiceContext.actorDid, the DID of the authenticated actor regardless of how the context was authenticated.sessionis set only for the legacy (app-password) path andoAuthSessionManageronly for the OAuth one, so neither answers that on its own and callers were left composing the two by hand.repois now defined in terms of it, so the two cannot drift. - feat: added
isAmbiguousFailure, a pure predicate reporting whether a caught error leaves it uncertain that the request reached the server. The retry engine already drew this distinction but only exposed it to aRetryStrategy; once retries were exhausted the original error was rethrown unchanged — aTimeoutExceptionor anhttp.ClientExceptioncannot carry an extra field — so a caller writing records could not tell a safe retry from one risking a duplicate. The retry layer now consumes the same predicate, so the classification callers see cannot drift from the behavior they observe. - feat:
atproto_core.dartnow re-exportsTidGeneratorfromat_primitives, alongside the existingAtUriandNSIDre-exports, so a caller allocating record keys ahead of a write does not need a direct dependency onat_primitives. - feat: added
ServiceContext.withHeaders, deriving a context that shares this one's session while carrying its own request headers. Mutable session state now lives in a holder the derived contexts share, so a refresh — including the deduplicated in-flight one — is seen by all of them. Headers belong to the client; the session belongs to the account.
- feat: added
-
2.2.022 Jul 2026Release notes
Open source →- feat: added
computeRecordCid, which returns the CID a PDS will assign to a record by canonically DAG-CBOR-encoding it and hashing to a CIDv1. This lets a caller reference a record before it is written — for example to chain reply references across records submitted in onecom.atproto.repo.applyWritesbatch. - chore: widen
at_primitivesto^1.2.0,multiformatsto^1.3.0, andxrpcto^1.1.3.
- feat: added
-
2.1.021 Jul 2026Release notes
Open source →- feat: added
ServiceContext.onSessionUpdated, a broadcast stream that emits the refreshedSessioneach time an expired access token is renewed.sessionalready reflected the new credentials, but nothing told the caller to read it back — and because refresh tokens are single-use, a caller that kept persisting the session it originally passed in stored a spent refresh token, so the next run restored a session that could no longer be refreshed. MirrorsOAuthSessionManager.onSessionUpdatedfor the legacy (app-password) path; it stays silent on OAuth-backed contexts. Concurrent requests that share one deduplicated refresh emit exactly one event.
- feat: added
-
2.0.116 Jul 2026Release notes
Open source →- docs: rewrite the README to document the actual public API —
Session/OAuthSession, JWT decoding (decodeJwt/Jwt), the pluggable retry engine (RetryStrategy,RetryConfig,RetryContext,RetryReason,RetryEvent,Jitter),BaseHttpService/ServiceContext,Blob/BlobRef,decodeCar,isValidAppPassword, and thexrpc/multiformats/cborre-exports — and frame the package as the shared core layeratproto/blueskybuild on. - docs: replace the placeholder
example/example.mdwith a runnableexample/example.dartcoveringRetryConfig/customRetryStrategy, JWT decoding,Blobserialization, and app-password validation. - chore: bump
xrpcto^1.1.2,at_primitivesto^1.1.1, andatproto_oauthto^0.5.1.
- docs: rewrite the README to document the actual public API —
-
2.0.016 Jul 2026Release notes
Open source →- feat!: OAuth requests are now driven by
OAuthSessionManager;ServiceContexttakesoAuthSessionManagerinstead ofoAuthSession, enabling transparent OAuth token auto-refresh. OAuth tokens are never JWT-decoded.restoreOAuthSession/OauthSessionExtensionremoved (opaque tokens). Legacy password-authSessionis unaffected. - fix: OAuth requests target the session's PDS even when the
OAuthSessionManagerrestores its session lazily — previously every request defaulted tobsky.social, causing spurious 401s. - fix: a caller-supplied
Authorizationheader (e.g. a service-auth Bearer token) is preserved instead of being overwritten by the session/DPoP token, fixing service-auth flows such as video upload. - fix: concurrent expired requests now share a single legacy-session refresh instead of issuing a refresh stampede.
- feat:
stream()accepts aserviceoverride and achannelFactory, and honors the configured protocol; theuse_dpop_nonceretry awaits the nonce write before retrying. - fix: a failing user-supplied DPoP nonce-cache write on the request success path is now contained instead of escaping as an uncaught asynchronous error, so a storage failure in
DPoPNonceCache.setcan no longer crash the app. - fix: the rate-limit retry wait now parses the HTTP-date form of
Retry-After(previously only delta-seconds was honored; a date silently degraded to plain backoff and could retry too early). - perf:
ServiceContext.servicecaches the resolved PDS endpoint per access JWT instead of base64/JSON-decoding the access token on every request when the did document has no#atproto_pdsservice. - feat: retries are now driven by a pluggable
RetryStrategy(FutureOr<Duration?> nextDelay(RetryContext)).RetryContextexposes the attempt count, failureRetryReason, request kind (query vs procedure), NSID, status code, and the server-providedRetry-After. ImplementRetryStrategyfor full control over backoff and which failures retry; the defaultRetryConfignow implements it. - fix: by default a procedure (
POST) is no longer retried after an ambiguous failure the server may already have applied (a timeout after the request was sent, a5xx, or an inconclusive connection reset), preventing duplicate writes. Queries (GET) and subscriptions still retry as before, and429/pre-connection network failures still retry for procedures. SetRetryConfig(retryProcedureOnAmbiguousFailure: true)to restore the previous unconditional behavior.
- feat!: OAuth requests are now driven by
-
1.3.013 Jul 2026Release notes
Open source →- feat: automatic access-token refresh —
Challengenow retries once after refreshing on a genuine401, with a pre-emptive refresh when the token is within 30s of expiry (theuse_dpop_noncepath is unchanged). - fix:
Challengenow retries429(respectingratelimit-reset/Retry-After),SocketException, andClientException, and preserves theXRPCResponse<T>type — previously onlyTimeoutExceptionand500were retried and the type was erased. - fix:
car_decoderhandles variable-length multihash CIDs and raises a typedCarExceptionon truncated input; tag-42 CID links are normalized to{$link: <cid>}so downstream keeps type info, and the triplejsonEncode/jsonDecoderound-trip is gone. - fix:
decodeCarnow normalizes plain (non-tagged) CBOR byte strings to{$bytes: <base64>}(standard base64, RFC 4648 section 4, no padding) per the atproto data model, instead of returning rawUint8List. - fix:
atprotoPdsEndpointkeeps an explicit port, falls back to the JWTaudwhen the did document has no#atproto_pds, and guards malformed did documents. - fix: caller-supplied headers can no longer override
Authorization/DPoP;dpop-noncelookup is case-insensitive. - fix: empty
$unknownmaps are stripped from the wire JSON. - fix: unify on the validating
NsidConverter; the non-validatingNSIDConverteralias is deprecated. - chore: bump
xrpcto^1.1.0,at_primitivesto^1.1.0,multiformatsto^1.1.0, andatproto_oauthto^0.4.0.
- feat: automatic access-token refresh —
-
1.2.210 Jul 2026Release notes
Open source →- fix: redact
accessJwt/refreshJwtinSession.toString()so credentials are not leaked through logs or crash reporters. - fix: forward the
headersargument inBaseHttpService.post(previously dropped). - fix: retry jitter is now inclusive
[min, max]and no longer throws aRangeErrorwhenmaxInSecondsis0. - chore: bump
atproto_oauthandmultiformats.
- fix: redact
-
1.2.120 May 2026 -
1.2.020 Feb 2026 -
1.1.020 Dec 2025Release notes
Open source →- Add optional $service parameter to video service methods (getJobStatus, getUploadLimits, uploadVideo).
- Export nanoid and @Protected annotation from atproto_core/internals.dart.
-
1.0.725 Sep 2025Release notes
Open source →- MIGRATION: Updated to use the consolidated
at_primitivespackage for all primitive AT Protocol types. - IMPROVEMENT: Simplified dependency management by adopting unified primitive types from
at_primitives.
- MIGRATION: Updated to use the consolidated
-
1.0.610 Aug 2025 -
1.0.510 Aug 2025Release notes
Open source →- chore: fix
WARNING: The annotation 'JsonSerializable.new' can only be used on classes..
- chore: fix
-
1.0.409 Aug 2025 -
1.0.306 Aug 2025 -
1.0.230 Jul 2025 -
1.0.128 Jul 2025 -
1.0.1-legacy28 Jul 2025 pre-releaseNothing published for this version
-
1.0.018 Jul 2025Release notes
Open source →Jwt.audis now nullable based onRFC 7519. (#1982)- Bump SDK constraint to '^3.8.0'.
-
1.0.0-preview.109 Jul 2024 pre-releaseNothing published for this version
-
1.0.0-preview.004 Jul 2024 pre-releaseNothing published for this version
-
1.0.0-legacy24 Jul 2025 pre-releaseNothing published for this version
-
0.11.207 Dec 2024 -
0.11.119 Nov 2024Release notes
Open source →- Retry if a DPoP nonce error occurs during the execution of
OAuthClient.refresh. - Add
restoreOAuthSessionfunction.
- Retry if a DPoP nonce error occurs during the execution of
-
0.11.016 Nov 2024Release notes
Open source →- Expose
atproto_oauthpackage. - Add
.oAuthSessionparameter onServiceContext. - Rename
AuthTokentoJwt.- Change type of
scopefrom enum toString - Rename
subjecttosub - Rename
expiresAttoexp - Rename
issuedAttoiat
- Change type of
- Rename extended getters on
Session- From
accessTokentoaccessTokenJwt - From
refreshTokentorefreshTokenJwt
- From
- Expose
-
0.10.604 Nov 2024Release notes
Open source →- Add
serviceparameter onServiceContext.getandServiceContext.post. (#1783)
- Add
-
0.10.502 Jul 2024Release notes
Open source →- Expose
NsidConverter. - Add
clientparameter for.getand.postonServiceContext.
- Expose
-
0.10.401 Jul 2024Release notes
Open source →- Expose
.atprotoPdsEndpointfrom as an extension ofSession. You can get specific pds endpoint based on did document.
- Expose
-
0.10.301 Jul 2024Release notes
Open source →- Change the type
.collectionproperty fromStringtoNSIDonAtUri. You need to do.collection.toString()when you want a string of collection. (#1551)
- Change the type
-
0.10.209 Jun 2024Release notes
Open source →- The
serviceis automatically resolved from the DID Document of the givenSession. (#1543)- If no authentication is performed and no
Sessionis passed, the defaultbsky.socialis used. - If the user passes a specific
service, it always respects the value of the user'sservice. - If something wrong happens for some reason, it uses
bsky.socialas default.
- If no authentication is performed and no
- The
-
0.10.106 Jun 2024 -
0.10.003 Jun 2024Release notes
Open source →- Add
.activeand.statusproperties onSessionobject. (#1516) - Move
BlobConverter,Blob,BlobReffromatprotopackage toatproto_core.
- Add
-
0.10.0-preview.201 Feb 2024 pre-releaseNothing published for this version
-
0.10.0-preview.129 Jan 2024 pre-releaseNothing published for this version
-
0.10.0-preview.021 Jan 2024 pre-releaseNothing published for this version
-
0.9.1028 May 2024 -
0.9.928 May 2024Release notes
Open source →- Add
appPassPrivilegedonAuthScope. (#1501) - Add
.headersproperty. Returns the merged headers with global headers and auth header.
- Add
-
0.9.818 Apr 2024Release notes
Open source → -
0.9.727 Mar 2024 -
0.9.625 Feb 2024 -
0.9.522 Feb 2024Release notes
Open source →- Added
.toUtcIso8601StringonServiceContext. (#1278) - Bump SDK constraint to '^3.3.0'.
- Added
-
0.9.418 Feb 2024Release notes
Open source →- Improved redundant error messages. Now it shows like
GET https://bsky.social/xrpc/com.atproto.identity.resolveHandle 400 Error: Params must have the property "handle". (#1253) - Exposed
.serviceand.relayServiceproperties onServiceContext. (#1254) - Added
parametersarg and you can pass bytes tobodyarg on.postmethod. (#1252) - BugFix: Made sure to check if the subscribeRepos blocks can be decoded. (#1239)
- Improved redundant error messages. Now it shows like
-
0.9.327 Jan 2024Release notes
Open source →- Upgrade dependencies. (#1217)
- Added
headersparameter for.getmethod onServiceContext.
-
0.9.230 Dec 2023 -
0.9.129 Dec 2023 -
0.9.025 Dec 2023 -
0.8.121 Dec 2023 -
0.8.019 Dec 2023 -
0.7.017 Dec 2023Release notes
Open source →- Removed
AuthTypeandClientResolver. Let the server handle whether authentication is required or not. (#1102)
- Removed
-
0.6.324 Nov 2023 -
0.6.224 Nov 2023 -
0.6.115 Nov 2023Release notes
Open source →- Added
BaseHttpService.post. (#999) - Fixed a bug that service names were not specified correctly when using stream endpoints.
- Added
-
0.6.009 Nov 2023Release notes
Open source →- Added HTTP specific client. (#989)
- Renamed from
UserContexttoAuthType.
-
0.5.901 Nov 2023Release notes
Open source → -
0.5.831 Oct 2023 -
0.5.728 Sep 2023 -
0.5.617 Sep 2023 -
0.5.514 Sep 2023