Commit Graph

1269 Commits

Author SHA1 Message Date
Samuel Newman a940fa1c80 remove use of URL.canParse 2026-08-13 22:13:52 +03:00
Samuel Newman e444177292 address review feedback across the stack
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:52 +03:00
Samuel Newman 37b7a7b0f9 migrate the logged-out feed fetch to a direct appview lex client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:52 +03:00
Samuel Newman b08683a202 fix comments the branding pass made stale
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:51 +03:00
Samuel Newman 854fa1f837 lint --fix 2026-08-13 22:13:51 +03:00
Samuel Newman 8da13e7511 drop the casts the dual-world layer needed
With every producer on the generated lexicons, the branded-string assertions at
these 30 sites are no-ops, and oxlint flags them. Also sorts the imports the
type flip disturbed and prunes the suppressions that no longer occur.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:50 +03:00
Samuel Newman 02173556ab drop @atproto/api from the dependency tree
The last references were stale comments; the package itself leaves
package.json, webpack's transpile list, and 102 packages from the lockfile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:50 +03:00
Samuel Newman ae0750099f collapse the dual-world type layer and delete the widening shims
The types/bsky post/profile/starterPack unions drop their @atproto/api arms,
and dangerousIsType/validate go with the old-world guards they wrapped. The
moderation subjects.ts widening shim and rich-text-helpers' asSdkFacets both
existed only to bridge branded and unbranded views, so their 55 and 14 callers
now go straight to @bsky.app/sdk/moderation and the raw facets.

Boundary fallout: lexicon token defs are camelCase schema objects needing
.value, and the branded string slots that the widening used to absorb are now
cast or branded at their producers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:50 +03:00
Samuel Newman 8c228c2e4f flip the lib type imports and move the xrpc error helpers off the old client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:49 +03:00
Samuel Newman 541a82c2dd move the bluesky labeler did to the sdk api constant
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:49 +03:00
Samuel Newman 2f482f2c0b repoint the last AtpAgent statics and drop the dead conversions
Five sites read `AtpAgent.appLabelers`, which the previous commit stopped
populating - a silent regression, since an empty static reads as "no
authorities" rather than failing. All now read `Client.appLabelers`, the static
that is actually configured:

- `lib/moderation.ts`'s `isAppLabeler`, which decides whether a labeler is
  non-removable in the UI;
- `preferences/moderation.ts`'s `useMyLabelersQuery`, which seeds the labeler
  list with the app authorities;
- `feed/custom.ts`'s hand-rolled logged-out `getFeed`, which reproduces the
  header lex would have emitted because the request bypasses the client.

`sessionAccountToSession` (the `AtpSessionData` conversion) had no callers left
once the bridge agent went, and the age assurance config read - the one
standalone `new AtpAgent` the age assurance slice deliberately left behind -
moves to the public appview client, which is what it was approximating.

That is the last `AtpAgent` in src. What remains of `@atproto/api` in the
session layer is types and `BSKY_LABELER_DID`, which S4d owns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:48 +03:00
Samuel Newman 64b0039c67 hold the three clients in the bundle and delete the bridge agent
The bundle becomes `{session, appviewClient, pdsClient, chatClient, service}`
and the hooks read those fields directly, so `useAgent` and the three
`agentTo*Client` memo maps go with the agent. The WeakMaps existed only because
clients were derived from a long-lived agent; a bundle that HOLDS its clients
gets identity stability for free.

The clients are now the sole producers of their own headers, which is what lets
`bridge-agent.ts` (442 lines) and `agent.ts` go:

- the appview client passes BLUESKY_PROXY_HEADER as its `service`, so it emits
  atproto-proxy itself rather than inheriting it from a configureProxy call
  sequenced after the PDS-targeting setup;
- labeler subscriptions go on the appview instance via `setLabelers`, and the
  global `;redact` authorities come from the `Client` static alone. Both halves
  of the double-emit hazard the previous slice documented are closed by there
  being one producer instead of two, so the appview client no longer suppresses
  `appLabelers` - only the PDS and chat clients do, because those services take
  no moderation authorities at all;
- `configureGlobalAppLabelers` drops its `AtpAgent.configure` half.

PDS routing for the pre-didDoc window is `routeSessionToPds`, a 10-line shim
replacing the manager's dispatchUrl/extractPdsUrl/identity-cache apparatus.
`PasswordSession` resolves each request against `extractPdsUrl(didDoc) ??
service`, so an entryway account with no didDoc yet - the synchronous resume
fast path, i.e. the common cold start - would send every request to the
entryway. The shim absolutizes against the stored url first, which survives
`new URL(path, base)` untouched. It pins that url for the bundle's lifetime
where the manager would have preferred a later didDoc endpoint; that only
differs if the account's PDS moved, and the next cold start pins the new one.
Four cases in clients-test cover this, including the two the old suite could
not express (pinned-vs-didDoc precedence, and didDoc routing with nothing
pinned).

`createPublicSessionBundle` now runs `configureModerationForGuest` itself. That
is a behavior fix, not a refactor: it populates the `Client.appLabelers` static
the public appview client reads, and with no agent left to stamp the header a
logged-out read would otherwise carry no moderation authorities.

finishPreparation, the kill-switch disposal, the redacted logging, refreshSession
and the expiry-rescue path are unchanged - only how the bundle is constructed
moved. Disposal is now just the hook kill: the clients hold no state, and every
request they make goes through the session's injected fetch.

bridge-agent-test.ts is deleted with its subject. clients-test.ts is rewritten
against session-built clients, keeping every header canary (exactly-once on the
appview, none on pds/chat, exact proxy values, the throwing client's cause
chain). The three provider suites and session-core-test are adapted in place -
their constructions change, their assertions do not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:48 +03:00
Samuel Newman 92408c62a6 migrate link resolution to the appview and chat clients
`resolveLink` took an agent and used it for four appview reads plus the chat
invite preview, so it now takes both clients as a `LinkResolvers` pair - the
caller cannot know which branch a URL will take until it is parsed. That was
the last DM_SERVICE_HEADERS site, so the constant is deleted.

`resolveGif` never touched the agent at all (it is pure URL metadata work on
what the picker already returned), so its parameter is dropped rather than
replaced, along with the one on `fetchResolveGifQuery`.

With the resolvers on clients, `apilib.post` loses the agent parameter the
previous slice kept solely for them, and `composerStateToDraft` takes the
resolver pair instead of minting a throwaway public agent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:48 +03:00
Samuel Newman 9aa6b49daf swap the moderation core to the sdk moderation module
Point the moderation primitives - the label definitions, the cause/UI/decision
types and the label-info hooks - at `@bsky.app/sdk/moderation` instead of
`@atproto/api`.

The two implementations are mutually unassignable: the sdk's subject types are
the generated `#/lexicons` views, so their `did`/`uri`/`cid` fields are
branded (`DidString`, `AtUriString`) where the `@atproto/api` views type the
same fields as plain `string`. That rules out a partial swap - a decision made
by one implementation cannot be read by the other - so the whole moderation
layer moves together.

`lib/moderation/subjects.ts` is the transitional seam for the brand mismatch.
Every `moderate*` entry point is re-exported through a wrapper that widens its
subject parameter to accept a view from either world, because many read paths
still emit `@atproto/api` views while the moderation runtime only ever reads
`.did`, `.labels` and `.viewer` - none of which the brand affects. It is
deleted in the `@atproto/api` removal pass.
2026-08-13 22:13:47 +03:00
Samuel Newman a40c199523 migrate the signup and onboarding profile writes to sdk actions
The post-signup and onboarding writes (setPersonalDetails, upsertProfile,
overwriteSavedFeeds, setInterestsPref) move onto sdk actions over the pds
client, and the starter-pack and contact-import reads move to the lex
clients. Every upsertProfile call now writes a lex blob directly, so the
toLegacyBlobRef bridge has no remaining callers and is deleted.
2026-08-13 22:13:46 +03:00
Samuel Newman 88bc368991 drop the agent url reads in link meta and push registration
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:46 +03:00
Samuel Newman 4f669812b9 thread an explicit dispatch url through the video upload service auth
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:46 +03:00
Samuel Newman 7d8391aeb2 migrate the post pipeline write and reply lookup to the clients
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:45 +03:00
Samuel Newman 83fdc95237 migrate the blob upload helper to the pds client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:45 +03:00
Samuel Newman 28313bb81c extract the post pipeline cid hasher with golden-cid fixtures
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:45 +03:00
Samuel Newman 3a970a7104 migrate the starter pack writes to the pds client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:45 +03:00
Samuel Newman 0c8cdba703 migrate the threadgate and postgate records to the pds client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:44 +03:00
Samuel Newman a6682ebf1d add a shared getRecord RecordNotFound classifier
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:13:44 +03:00
Samuel Newman 2beb63fb2d migrate RichText to the SDK and resolve facets via the appview
The two RichText classes are not mutually assignable - `UnicodeString` has a
private field and the SDK brands `did`/`uri` as template literal types - so
every producer and consumer of a RichText instance has to move in one step.

`detectFacets` now takes a lex client instead of the legacy agent, which is
what removes the last hard agent dependency from these files. Handle
resolution is an appview job, so the appview client is threaded in: through
`useAppviewClient` in the hooks and dialogs, and through a new
`appviewClient` option on `apilib.post` (Composer already had the client to
hand). The rest of the post pipeline still writes through the agent.

Facet feature checks move from the `AppBskyRichtextFacet` validators to the
generated `#/lexicons` schemas, matching how the rest of the app narrows
lexicon types.

Display sinks still read facets off `@atproto/api` view types, which are the
same lexicon but typed with plain strings. `asSdkFacets` widens them at those
call sites and goes away once the view types come from the SDK too.
2026-08-13 21:50:54 +03:00
Samuel Newman abf8ba0993 route moderation reports through the appview client with per-call proxying
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:54 +03:00
Samuel Newman cc295497fe add the arbitrary-service pre-auth client factory
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:53 +03:00
Samuel Newman 8b4f284786 migrate the custom, merge and home feed apis to the appview client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:53 +03:00
Samuel Newman 234f34f4d5 migrate the single-source feed api classes to the appview client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:53 +03:00
Samuel Newman dc9741d8ba add the chat proxy service constant
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:50 +03:00
Samuel Newman b02754f8b8 apply tweaked version of matthieu's suggestion 2026-08-13 21:50:50 +03:00
Samuel Newman f3a2674b9b match xrpc errors against the method schema
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:50 +03:00
Samuel Newman 7fee516d4c add the lex client seam over the bridge agent
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:50:50 +03:00
Samuel Newman 3d91143c80 drop direct lex-client dep, import from @atproto/lex
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:41:06 +03:00
Samuel Newman 6df3986c2b surface lex error messages in cleanError
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:41:05 +03:00
Samuel Newman 21d67da9a9 match lex errors with instanceof, drop getErrorName
`getErrorName` erased the typed error classes by flattening everything to a
string code. Anchor on the classes instead: `LexAuthFactorError` for the login
2FA branch, `XrpcResponseError` for the signup error codes.

`@atproto/lex-client` stays a direct dependency because `XrpcResponseError` is
used at runtime for `instanceof`. It is already in the runtime graph via
`@atproto/lex-password-session`, so the direct declaration adds no bundle
weight; it makes the import legal under pnpm's strict layout and pins the
version so both packages share one `LexError` identity.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:41:04 +03:00
Samuel Newman 1d279dc894 adapt error classification and email state to the lex session core
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:41:04 +03:00
Samuel Newman d727be8c1a Fix profile icon on custom feeds (#11408)
Co-authored-by: DS Boyce <260543580+ds-boyce@users.noreply.github.com>
2026-08-06 16:37:21 -07:00
DS Boyce 1c349ad7da Add timestamp field to video report dialog (#11339) 2026-08-06 12:11:05 -07:00
Spence Pope 5cf6d8fa21 Use toolbox video compressor (#11246) 2026-08-06 08:16:18 -04:00
Spence Pope 17a8fe87c2 APP-2793: harden multipart video uploads (#11366) 2026-08-05 10:15:16 -04:00
Spence Pope 0ccc029716 Allow feature-gated 10-minute video uploads (#11388) 2026-08-05 10:15:06 -04:00
Samuel Newman c2ceb8057f Handle camera cancellation (#11322) 2026-08-03 06:25:42 -07:00
Samuel Newman ce28129674 Add nicer loading screen while OTA is loading (#9499) 2026-07-31 09:39:26 -07:00
Samuel Newman 07c34a6548 Fix PR OTA deployments reverting after apply (#11338)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 23:30:42 +03:00
Samuel Newman 17c1ee4869 Handle PR OTA version mismatches and failures (#11330) 2026-07-30 07:40:49 -07:00
Spence Pope a35c4ac4ba APP-2670: add multipart video upload transport (#11222) 2026-07-29 12:54:03 -04:00
Samuel Newman de348db116 Show a non-standard OTA channel notice in the drawer (#11288)
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-28 06:59:17 -07:00
Samuel Newman 0e63434bb4 Reenable wake-from-background Android OTA (#11298) 2026-07-27 09:20:10 -07:00
Tomasz Zawadzki 2b9deeeb6a Migrate runOnUI/runOnJS to scheduleOnUI/scheduleOnRN (#11249) 2026-07-26 12:00:35 -07:00
Samuel Newman 19b0d89313 Update react-native-uitextview (#11264) 2026-07-24 07:40:46 -07:00