finish phase 3: type-only codemod and zero non-bridge @atproto/api imports
Task 8: codemod repointed 150 namespace-type files to #/lexicons (AppBskyFeedDefs.PostView -> app.bsky.feed.defs.PostView, .Record -> .Main) plus ~105 hand-fixed consumers (composer/video state, DebugMod, Profile, onboarding, dialogs). DM_SERVICE_HEADERS deleted; last chat call sites on the chat client. RichText.tsx flipped to SDK-only. Remaining @atproto/api importers: the three session bridge files, the deliberate dual-world matcher in lib/xrpc-error.ts, and test fixtures. toLex boundary casts are TODO(phase4)-tagged for bridge removal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vendored
+28
-21
@@ -1,9 +1,5 @@
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import {
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyEmbedRecordWithMedia,
|
||||
type AppBskyFeedDefs,
|
||||
} from '@atproto/api'
|
||||
import {type AtUriString} from '@atproto/syntax'
|
||||
import {type QueryClient} from '@tanstack/react-query'
|
||||
import {EventEmitter} from 'eventemitter3'
|
||||
|
||||
@@ -15,6 +11,8 @@ import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '#/state/qu
|
||||
import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes'
|
||||
import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '#/state/queries/search-posts-v2'
|
||||
import {findAllPostsInQueryData as findAllPostsInThreadV2QueryData} from '#/state/queries/usePostThread/queryCache'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {castAsShadow, type Shadow} from './types'
|
||||
export type {Shadow} from './types'
|
||||
|
||||
@@ -22,7 +20,10 @@ export interface PostShadow {
|
||||
likeUri: string | undefined
|
||||
repostUri: string | undefined
|
||||
isDeleted: boolean
|
||||
embed: AppBskyEmbedRecord.View | AppBskyEmbedRecordWithMedia.View | undefined
|
||||
embed:
|
||||
| app.bsky.embed.record.View
|
||||
| app.bsky.embed.recordWithMedia.View
|
||||
| undefined
|
||||
pinned: boolean
|
||||
optimisticReplyCount: number | undefined
|
||||
bookmarked: boolean | undefined
|
||||
@@ -32,7 +33,7 @@ export const POST_TOMBSTONE = Symbol('PostTombstone')
|
||||
|
||||
const emitter = new EventEmitter()
|
||||
const shadows: WeakMap<
|
||||
AppBskyFeedDefs.PostView,
|
||||
app.bsky.feed.defs.PostView,
|
||||
Partial<PostShadow>
|
||||
> = new WeakMap()
|
||||
|
||||
@@ -40,13 +41,13 @@ const shadows: WeakMap<
|
||||
* Use with caution! This function returns the raw shadow data for a post.
|
||||
* Prefer using `usePostShadow`.
|
||||
*/
|
||||
export function dangerousGetPostShadow(post: AppBskyFeedDefs.PostView) {
|
||||
export function dangerousGetPostShadow(post: app.bsky.feed.defs.PostView) {
|
||||
return shadows.get(post)
|
||||
}
|
||||
|
||||
export function usePostShadow(
|
||||
post: AppBskyFeedDefs.PostView,
|
||||
): Shadow<AppBskyFeedDefs.PostView> | typeof POST_TOMBSTONE {
|
||||
post: app.bsky.feed.defs.PostView,
|
||||
): Shadow<app.bsky.feed.defs.PostView> | typeof POST_TOMBSTONE {
|
||||
const [shadow, setShadow] = useState(() => shadows.get(post))
|
||||
const [prevPost, setPrevPost] = useState(post)
|
||||
if (post !== prevPost) {
|
||||
@@ -74,9 +75,9 @@ export function usePostShadow(
|
||||
}
|
||||
|
||||
function mergeShadow(
|
||||
post: AppBskyFeedDefs.PostView,
|
||||
post: app.bsky.feed.defs.PostView,
|
||||
shadow: Partial<PostShadow>,
|
||||
): Shadow<AppBskyFeedDefs.PostView> | typeof POST_TOMBSTONE {
|
||||
): Shadow<app.bsky.feed.defs.PostView> | typeof POST_TOMBSTONE {
|
||||
if (shadow.isDeleted) {
|
||||
return POST_TOMBSTONE
|
||||
}
|
||||
@@ -125,16 +126,16 @@ function mergeShadow(
|
||||
let embed: typeof post.embed
|
||||
if ('embed' in shadow) {
|
||||
if (
|
||||
(AppBskyEmbedRecord.isView(post.embed) &&
|
||||
AppBskyEmbedRecord.isView(shadow.embed)) ||
|
||||
(AppBskyEmbedRecordWithMedia.isView(post.embed) &&
|
||||
AppBskyEmbedRecordWithMedia.isView(shadow.embed))
|
||||
(bsky.isType(app.bsky.embed.record.view, post.embed) &&
|
||||
bsky.isType(app.bsky.embed.record.view, shadow.embed)) ||
|
||||
(bsky.isType(app.bsky.embed.recordWithMedia.view, post.embed) &&
|
||||
bsky.isType(app.bsky.embed.recordWithMedia.view, shadow.embed))
|
||||
) {
|
||||
embed = shadow.embed
|
||||
embed = shadow.embed as typeof post.embed
|
||||
}
|
||||
}
|
||||
|
||||
return castAsShadow({
|
||||
return castAsShadow<app.bsky.feed.defs.PostView>({
|
||||
...post,
|
||||
embed: embed || post.embed,
|
||||
likeCount: likeCount,
|
||||
@@ -143,8 +144,14 @@ function mergeShadow(
|
||||
bookmarkCount: bookmarkCount,
|
||||
viewer: {
|
||||
...(post.viewer || {}),
|
||||
like: 'likeUri' in shadow ? shadow.likeUri : post.viewer?.like,
|
||||
repost: 'repostUri' in shadow ? shadow.repostUri : post.viewer?.repost,
|
||||
like:
|
||||
'likeUri' in shadow
|
||||
? (shadow.likeUri as AtUriString | undefined)
|
||||
: post.viewer?.like,
|
||||
repost:
|
||||
'repostUri' in shadow
|
||||
? (shadow.repostUri as AtUriString | undefined)
|
||||
: post.viewer?.repost,
|
||||
pinned: 'pinned' in shadow ? shadow.pinned : post.viewer?.pinned,
|
||||
bookmarked:
|
||||
'bookmarked' in shadow ? shadow.bookmarked : post.viewer?.bookmarked,
|
||||
@@ -169,7 +176,7 @@ export function updatePostShadow(
|
||||
function* findPostsInCache(
|
||||
queryClient: QueryClient,
|
||||
uri: string,
|
||||
): Generator<AppBskyFeedDefs.PostView, void> {
|
||||
): Generator<app.bsky.feed.defs.PostView, void> {
|
||||
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {
|
||||
yield post
|
||||
}
|
||||
|
||||
Vendored
+6
-4
@@ -1,5 +1,4 @@
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import {type AppBskyActorDefs, type AppBskyNotificationDefs} from '@atproto/api'
|
||||
import {type QueryClient} from '@tanstack/react-query'
|
||||
import {EventEmitter} from 'eventemitter3'
|
||||
|
||||
@@ -33,6 +32,7 @@ import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersForDiscover
|
||||
import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersForExploreQueryData} from '#/state/queries/trending/useGetSuggestedUsersForExploreQuery'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInSuggestedUsersForSeeMoreQueryData} from '#/state/queries/trending/useGetSuggestedUsersForSeeMoreQuery'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInPostThreadV2QueryData} from '#/state/queries/usePostThread/queryCache'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {castAsShadow, type Shadow} from './types'
|
||||
|
||||
@@ -42,9 +42,11 @@ export interface ProfileShadow {
|
||||
followingUri: string | undefined
|
||||
muted: boolean | undefined
|
||||
blockingUri: string | undefined
|
||||
verification: AppBskyActorDefs.VerificationState
|
||||
status: AppBskyActorDefs.StatusView | undefined
|
||||
activitySubscription: AppBskyNotificationDefs.ActivitySubscription | undefined
|
||||
verification: app.bsky.actor.defs.VerificationState
|
||||
status: app.bsky.actor.defs.StatusView | undefined
|
||||
activitySubscription:
|
||||
| app.bsky.notification.defs.ActivitySubscription
|
||||
| undefined
|
||||
}
|
||||
|
||||
const shadows: WeakMap<
|
||||
|
||||
+13
-12
@@ -7,7 +7,7 @@ import {
|
||||
useRef,
|
||||
} from 'react'
|
||||
import {AppState, type AppStateStatus} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {type AtUriString} from '@atproto/syntax'
|
||||
import throttle from 'lodash.throttle'
|
||||
|
||||
import {PROD_FEEDS, STAGING_FEEDS} from '#/lib/constants'
|
||||
@@ -22,12 +22,13 @@ import {
|
||||
} from '#/state/queries/post-feed'
|
||||
import {getItemsForFeedback} from '#/view/com/posts/PostFeed'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import {useAgent} from './session'
|
||||
|
||||
export const FEEDBACK_FEEDS = [...PROD_FEEDS, ...STAGING_FEEDS]
|
||||
|
||||
export const THIRD_PARTY_ALLOWED_INTERACTIONS = new Set<
|
||||
AppBskyFeedDefs.Interaction['event']
|
||||
app.bsky.feed.defs.Interaction['event']
|
||||
>([
|
||||
// These are explicit actions and are therefore fine to send.
|
||||
'app.bsky.feed.defs#requestLess',
|
||||
@@ -45,7 +46,7 @@ export const THIRD_PARTY_ALLOWED_INTERACTIONS = new Set<
|
||||
export type StateContext = {
|
||||
enabled: boolean
|
||||
onItemSeen: (item: any) => void
|
||||
sendInteraction: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||
sendInteraction: (interaction: app.bsky.feed.defs.Interaction) => void
|
||||
feedDescriptor: FeedDescriptor | undefined
|
||||
feedSourceInfo: FeedSourceInfo | undefined
|
||||
}
|
||||
@@ -53,7 +54,7 @@ export type StateContext = {
|
||||
const stateContext = createContext<StateContext>({
|
||||
enabled: false,
|
||||
onItemSeen: (_item: any) => {},
|
||||
sendInteraction: (_interaction: AppBskyFeedDefs.Interaction) => {},
|
||||
sendInteraction: (_interaction: app.bsky.feed.defs.Interaction) => {},
|
||||
feedDescriptor: undefined,
|
||||
feedSourceInfo: undefined,
|
||||
})
|
||||
@@ -82,7 +83,7 @@ export function useFeedFeedback(
|
||||
const history = useRef<
|
||||
// Use a WeakSet so that we don't need to clear it.
|
||||
// This assumes that referential identity of slice items maps 1:1 to feed (re)fetches.
|
||||
WeakSet<FeedPostSliceItem | AppBskyFeedDefs.Interaction>
|
||||
WeakSet<FeedPostSliceItem | app.bsky.feed.defs.Interaction>
|
||||
>(new WeakSet())
|
||||
|
||||
const flushEvents = useCallback(
|
||||
@@ -206,7 +207,7 @@ export function useFeedFeedback(
|
||||
history.current.add(postItem)
|
||||
queue.current.add(
|
||||
toString({
|
||||
item: postItem.uri,
|
||||
item: postItem.uri as AtUriString,
|
||||
event: 'app.bsky.feed.defs#interactionSeen',
|
||||
feedContext,
|
||||
reqId,
|
||||
@@ -220,7 +221,7 @@ export function useFeedFeedback(
|
||||
)
|
||||
|
||||
const sendInteraction = useCallback(
|
||||
(interaction: AppBskyFeedDefs.Interaction) => {
|
||||
(interaction: app.bsky.feed.defs.Interaction) => {
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
@@ -268,7 +269,7 @@ export function isDiscoverFeed(feed?: FeedDescriptor) {
|
||||
function isInteractionAllowed(
|
||||
enabled: boolean,
|
||||
feed: FeedSourceFeedInfo | undefined,
|
||||
interaction: AppBskyFeedDefs.Interaction['event'],
|
||||
interaction: app.bsky.feed.defs.Interaction['event'],
|
||||
) {
|
||||
if (!enabled || !feed) {
|
||||
return false
|
||||
@@ -277,15 +278,15 @@ function isInteractionAllowed(
|
||||
return isDiscover ? true : THIRD_PARTY_ALLOWED_INTERACTIONS.has(interaction)
|
||||
}
|
||||
|
||||
function toString(interaction: AppBskyFeedDefs.Interaction): string {
|
||||
function toString(interaction: app.bsky.feed.defs.Interaction): string {
|
||||
return `${interaction.item}|${interaction.event}|${
|
||||
interaction.feedContext || ''
|
||||
}|${interaction.reqId || ''}`
|
||||
}
|
||||
|
||||
function toInteraction(str: string): AppBskyFeedDefs.Interaction {
|
||||
function toInteraction(str: string): app.bsky.feed.defs.Interaction {
|
||||
const [item, event, feedContext, reqId] = str.split('|')
|
||||
return {item, event, feedContext, reqId}
|
||||
return {item: item as AtUriString, event, feedContext, reqId}
|
||||
}
|
||||
|
||||
type AggregatedStats = {
|
||||
@@ -304,7 +305,7 @@ function createAggregatedStats(): AggregatedStats {
|
||||
|
||||
function sendOrAggregateInteractionsForStats(
|
||||
stats: AggregatedStats,
|
||||
interactions: AppBskyFeedDefs.Interaction[],
|
||||
interactions: app.bsky.feed.defs.Interaction[],
|
||||
) {
|
||||
for (let interaction of interactions) {
|
||||
switch (interaction.event) {
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
parseConvoView,
|
||||
} from '#/components/dms/util'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {app, chat} from '#/lexicons'
|
||||
import {type app, chat} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const logger = Logger.create(Logger.Context.ConversationAgent)
|
||||
|
||||
@@ -3,7 +3,7 @@ import {type Client} from '@atproto/lex-client'
|
||||
|
||||
import {type MessagesEventBus} from '#/state/messages/events/agent'
|
||||
import {type ConvoWithDetails} from '#/components/dms/util'
|
||||
import {app, type chat} from '#/lexicons'
|
||||
import {type app, type chat} from '#/lexicons'
|
||||
|
||||
export type ConvoParams = {
|
||||
convoId: string
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import {createContext, useContext} from 'react'
|
||||
import {
|
||||
type AppBskyLabelerDefs,
|
||||
type InterpretedLabelValueDefinition,
|
||||
} from '@atproto/api'
|
||||
import {type InterpretedLabelValueDefinition} from '@bsky.app/sdk/moderation'
|
||||
|
||||
import {type app} from '#/lexicons'
|
||||
import {useLabelDefinitionsQuery} from '../queries/preferences'
|
||||
|
||||
interface StateContext {
|
||||
labelDefs: Record<string, InterpretedLabelValueDefinition[]>
|
||||
labelers: AppBskyLabelerDefs.LabelerViewDetailed[]
|
||||
labelers: app.bsky.labeler.defs.LabelerViewDetailed[]
|
||||
}
|
||||
|
||||
const stateContext = createContext<StateContext>({
|
||||
|
||||
@@ -55,14 +55,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
hiddenPosts: (hiddenPosts ||
|
||||
[]) as ModerationOpts['prefs']['hiddenPosts'],
|
||||
},
|
||||
/*
|
||||
* TODO(phase4): drop this cast once `#/state/preferences/label-defs`
|
||||
* flips its `InterpretedLabelValueDefinition` source from `@atproto/api`
|
||||
* to `@bsky.app/sdk/moderation`. The value is already produced by the
|
||||
* SDK's `interpretLabelValueDefinitions` (see `../queries/preferences`);
|
||||
* only the intermediate context type is still old-world.
|
||||
*/
|
||||
labelDefs: labelDefs,
|
||||
labelDefs,
|
||||
}
|
||||
}, [override, userDid, labelDefs, moderationPrefs, hiddenPosts])
|
||||
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
import {useCallback} from 'react'
|
||||
import {
|
||||
type $Typed,
|
||||
AtpAgent,
|
||||
ChatBskyGroupDefs,
|
||||
type ChatBskyGroupGetJoinLinkPreviews,
|
||||
} from '@atproto/api'
|
||||
import {type $Typed} from '@atproto/lex'
|
||||
import {Client} from '@atproto/lex-client'
|
||||
import {toDatetimeString} from '@atproto/syntax'
|
||||
import {type QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {CHAT_SERVICE, DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {CHAT_SERVICE} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {STALE} from '#/state/queries/index'
|
||||
import {createQueryKey, type StructuredQueryKey} from '#/state/queries/util'
|
||||
import {type SessionAgent, useAgent} from '#/state/session'
|
||||
import {useMaybeChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
/**
|
||||
* Unauthenticated client pointed directly at the chat service, for the
|
||||
* logged-out join-link preview path (mirrors the old public `AtpAgent` at
|
||||
* `CHAT_SERVICE`). Chat requires no `atproto-proxy` here since we hit the
|
||||
* service directly.
|
||||
*/
|
||||
let publicChatClient: Client | undefined
|
||||
function getPublicChatClient(): Client {
|
||||
publicChatClient ??= new Client({service: CHAT_SERVICE})
|
||||
return publicChatClient
|
||||
}
|
||||
|
||||
/**
|
||||
* The three preview shapes we currently support. Excludes the `{$type: string}`
|
||||
@@ -19,15 +30,17 @@ import {type SessionAgent, useAgent} from '#/state/session'
|
||||
* `ChatInvitePreview` for that.
|
||||
*/
|
||||
export type KnownChatInvitePreview =
|
||||
| $Typed<ChatBskyGroupDefs.JoinLinkPreviewView>
|
||||
| $Typed<ChatBskyGroupDefs.DisabledJoinLinkPreviewView>
|
||||
| $Typed<ChatBskyGroupDefs.InvalidJoinLinkPreviewView>
|
||||
| $Typed<chat.bsky.group.defs.JoinLinkPreviewView>
|
||||
| $Typed<chat.bsky.group.defs.DisabledJoinLinkPreviewView>
|
||||
| $Typed<chat.bsky.group.defs.InvalidJoinLinkPreviewView>
|
||||
|
||||
/**
|
||||
* The full open-union shape, including the `{$type: string}` fallback for
|
||||
* future variants.
|
||||
* The full open-union shape, including the open-union fallback for future
|
||||
* variants. Sourced from the endpoint's output element type so it matches the
|
||||
* lex `Unknown$TypedObject` fallback exactly.
|
||||
*/
|
||||
export type ChatInvitePreview = KnownChatInvitePreview | {$type: string}
|
||||
export type ChatInvitePreview =
|
||||
chat.bsky.group.getJoinLinkPreviews.$OutputBody['joinLinkPreviews'][number]
|
||||
|
||||
/**
|
||||
* Narrows a preview to one of the three known variants, filtering out the
|
||||
@@ -37,9 +50,9 @@ export function isKnownJoinLinkPreview(
|
||||
preview: unknown,
|
||||
): preview is KnownChatInvitePreview {
|
||||
return (
|
||||
ChatBskyGroupDefs.isJoinLinkPreviewView(preview) ||
|
||||
ChatBskyGroupDefs.isDisabledJoinLinkPreviewView(preview) ||
|
||||
ChatBskyGroupDefs.isInvalidJoinLinkPreviewView(preview)
|
||||
bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, preview) ||
|
||||
bsky.isType(chat.bsky.group.defs.disabledJoinLinkPreviewView, preview) ||
|
||||
bsky.isType(chat.bsky.group.defs.invalidJoinLinkPreviewView, preview)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -88,7 +101,7 @@ export function setJoinLinkPreviewRequestedForCode(
|
||||
code: string,
|
||||
requested: boolean,
|
||||
) {
|
||||
queryClient.setQueriesData<ChatBskyGroupGetJoinLinkPreviews.OutputSchema>(
|
||||
queryClient.setQueriesData<chat.bsky.group.getJoinLinkPreviews.$OutputBody>(
|
||||
{
|
||||
predicate: query => {
|
||||
const [root, args] = query.queryKey as Partial<
|
||||
@@ -107,14 +120,16 @@ export function setJoinLinkPreviewRequestedForCode(
|
||||
...old,
|
||||
joinLinkPreviews: old.joinLinkPreviews.map(preview => {
|
||||
if (
|
||||
ChatBskyGroupDefs.isJoinLinkPreviewView(preview) &&
|
||||
bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, preview) &&
|
||||
preview.code === code
|
||||
) {
|
||||
return {
|
||||
...preview,
|
||||
viewer: {
|
||||
...preview.viewer,
|
||||
requestedAt: requested ? new Date().toISOString() : undefined,
|
||||
requestedAt: requested
|
||||
? toDatetimeString(new Date())
|
||||
: undefined,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -141,12 +156,12 @@ export function invalidateJoinLinkPreviewsForConvo(
|
||||
const [root] = query.queryKey
|
||||
if (root !== joinLinkPreviewQueryKeyRoot) return false
|
||||
const data = query.state.data as
|
||||
| ChatBskyGroupGetJoinLinkPreviews.OutputSchema
|
||||
| chat.bsky.group.getJoinLinkPreviews.$OutputBody
|
||||
| undefined
|
||||
return (
|
||||
data?.joinLinkPreviews.some(
|
||||
preview =>
|
||||
ChatBskyGroupDefs.isJoinLinkPreviewView(preview) &&
|
||||
bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, preview) &&
|
||||
preview.convoId === convoId,
|
||||
) ?? false
|
||||
)
|
||||
@@ -155,22 +170,20 @@ export function invalidateJoinLinkPreviewsForConvo(
|
||||
}
|
||||
|
||||
async function fetchJoinLinkPreviews({
|
||||
agent,
|
||||
chatClient,
|
||||
codes,
|
||||
hasSession,
|
||||
}: {
|
||||
agent: SessionAgent
|
||||
/**
|
||||
* Authed chat client (proxied to the chat service via `atproto-proxy`), or
|
||||
* null when logged out - the logged-out path uses the public chat client.
|
||||
*/
|
||||
chatClient: Client | null
|
||||
codes: string[]
|
||||
hasSession: boolean
|
||||
}) {
|
||||
const previewAgent = new AtpAgent({service: CHAT_SERVICE})
|
||||
const res = hasSession
|
||||
? await agent.chat.bsky.group.getJoinLinkPreviews(
|
||||
{codes},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
: await previewAgent.chat.bsky.group.getJoinLinkPreviews({codes})
|
||||
return res.data
|
||||
const client = hasSession && chatClient ? chatClient : getPublicChatClient()
|
||||
return await client.call(chat.bsky.group.getJoinLinkPreviews, {codes})
|
||||
}
|
||||
|
||||
export function useJoinLinkPreviewsQuery({
|
||||
@@ -186,16 +199,16 @@ export function useJoinLinkPreviewsQuery({
|
||||
* Seed the query with an already-known preview (e.g. a DM message embed
|
||||
* already carries the resolved view), avoiding a duplicate fetch.
|
||||
*/
|
||||
initialData?: ChatBskyGroupGetJoinLinkPreviews.OutputSchema
|
||||
initialData?: chat.bsky.group.getJoinLinkPreviews.$OutputBody
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
const chatClient = useMaybeChatClient()
|
||||
|
||||
return useQuery({
|
||||
queryKey: createJoinLinkPreviewQueryKey({codes: codes ?? [], hasSession}),
|
||||
queryFn: async () => {
|
||||
if (!codes) throw new Error('No invite code')
|
||||
try {
|
||||
return await fetchJoinLinkPreviews({agent, codes, hasSession})
|
||||
return await fetchJoinLinkPreviews({chatClient, codes, hasSession})
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch join link preview', {safeMessage: error})
|
||||
throw error
|
||||
@@ -208,13 +221,13 @@ export function useJoinLinkPreviewsQuery({
|
||||
}
|
||||
|
||||
export function usePrefetchJoinLinkPreviews() {
|
||||
const agent = useAgent()
|
||||
const chatClient = useMaybeChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return ({codes, hasSession}: {codes: string[]; hasSession: boolean}) => {
|
||||
return queryClient.prefetchQuery({
|
||||
queryKey: createJoinLinkPreviewQueryKey({codes, hasSession}),
|
||||
queryFn: () => fetchJoinLinkPreviews({agent, codes, hasSession}),
|
||||
queryFn: () => fetchJoinLinkPreviews({chatClient, codes, hasSession}),
|
||||
staleTime: STALE.SECONDS.FIFTEEN,
|
||||
})
|
||||
}
|
||||
@@ -226,7 +239,7 @@ export function usePrefetchJoinLinkPreviews() {
|
||||
* Returns undefined if the preview can't be resolved.
|
||||
*/
|
||||
export function useGetJoinLinkPreview() {
|
||||
const agent = useAgent()
|
||||
const chatClient = useMaybeChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useCallback(
|
||||
@@ -241,7 +254,7 @@ export function useGetJoinLinkPreview() {
|
||||
const data = await queryClient.fetchQuery({
|
||||
queryKey: createJoinLinkPreviewQueryKey({codes: [code], hasSession}),
|
||||
queryFn: () =>
|
||||
fetchJoinLinkPreviews({agent, codes: [code], hasSession}),
|
||||
fetchJoinLinkPreviews({chatClient, codes: [code], hasSession}),
|
||||
staleTime: STALE.SECONDS.FIFTEEN,
|
||||
})
|
||||
const found = data.joinLinkPreviews[0]
|
||||
@@ -251,6 +264,6 @@ export function useGetJoinLinkPreview() {
|
||||
return undefined
|
||||
}
|
||||
},
|
||||
[agent, queryClient],
|
||||
[chatClient, queryClient],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {type AtIdentifierString} from '@atproto/syntax'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
@@ -5,14 +6,15 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
import {logger} from '#/logger'
|
||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {app, type com} from '#/lexicons'
|
||||
import {updatePostShadow} from '../cache/post-shadow'
|
||||
import {useAgent, useSession} from '../session'
|
||||
import {useAppviewClient, useSession} from '../session'
|
||||
import {useProfileUpdateMutation} from './profile'
|
||||
|
||||
export function usePinnedPostMutation() {
|
||||
const {_} = useLingui()
|
||||
const {currentAccount} = useSession()
|
||||
const agent = useAgent()
|
||||
const appviewClient = useAppviewClient()
|
||||
const queryClient = useQueryClient()
|
||||
const {mutateAsync: profileUpdateMutate} = useProfileUpdateMutation()
|
||||
|
||||
@@ -33,8 +35,8 @@ export function usePinnedPostMutation() {
|
||||
|
||||
// get the currently pinned post so we can optimistically remove the pin from it
|
||||
if (!currentAccount) throw new Error('Not signed in')
|
||||
const {data: profile} = await agent.getProfile({
|
||||
actor: currentAccount.did,
|
||||
const profile = await appviewClient.call(app.bsky.actor.getProfile, {
|
||||
actor: currentAccount.did as AtIdentifierString,
|
||||
})
|
||||
prevPinnedPost = profile.pinnedPost?.uri
|
||||
if (prevPinnedPost && prevPinnedPost !== postUri) {
|
||||
@@ -45,14 +47,15 @@ export function usePinnedPostMutation() {
|
||||
profile,
|
||||
updates: existing => {
|
||||
existing.pinnedPost = pinCurrentPost
|
||||
? {uri: postUri, cid: postCid}
|
||||
? ({
|
||||
uri: postUri,
|
||||
cid: postCid,
|
||||
} as com.atproto.repo.strongRef.Main)
|
||||
: undefined
|
||||
return existing
|
||||
},
|
||||
checkCommitted: res =>
|
||||
pinCurrentPost
|
||||
? res.data.pinnedPost?.uri === postUri
|
||||
: !res.data.pinnedPost,
|
||||
pinCurrentPost ? res.pinnedPost?.uri === postUri : !res.pinnedPost,
|
||||
})
|
||||
|
||||
if (pinCurrentPost) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {preferencesQueryKey} from '#/state/queries/preferences'
|
||||
import {usePdsClient} from '#/state/session'
|
||||
import {app} from '#/lexicons'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export function usePostInteractionSettingsMutation({
|
||||
onError,
|
||||
|
||||
@@ -203,5 +203,5 @@ export function getMaybeDetachedQuoteEmbed({
|
||||
}
|
||||
|
||||
export const embeddingRules = {
|
||||
disableRule: {$type: 'app.bsky.feed.postgate#disableRule'},
|
||||
disableRule: {$type: 'app.bsky.feed.postgate#disableRule'} as const,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {useCallback, useMemo, useRef, useState} from 'react'
|
||||
import {type AppBskyUnspeccedGetPostThreadV2} from '@atproto/api'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import debounce from 'lodash.debounce'
|
||||
|
||||
@@ -10,10 +9,11 @@ import {
|
||||
} from '#/state/queries/preferences'
|
||||
import {type ThreadViewPreferences} from '#/state/queries/preferences/types'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import {type Literal} from '#/types/utils'
|
||||
|
||||
export type ThreadSortOption = Literal<
|
||||
AppBskyUnspeccedGetPostThreadV2.QueryParams['sort'],
|
||||
app.bsky.unspecced.getPostThreadV2.$Params['sort'],
|
||||
string
|
||||
>
|
||||
export type ThreadViewOption = 'linear' | 'tree'
|
||||
|
||||
@@ -275,7 +275,7 @@ export function useProfileFollowMutationQueue(
|
||||
did,
|
||||
})
|
||||
userActionHistory.follow([did])
|
||||
return uri
|
||||
return uri as AtUriString
|
||||
} else {
|
||||
if (prevFollowingUri) {
|
||||
await unfollowMutation.mutateAsync({
|
||||
@@ -337,7 +337,7 @@ export function useProfileFollowMutationQueue(
|
||||
if (finalFollowingUri) {
|
||||
void client
|
||||
.call(app.bsky.graph.getSuggestedFollowsByActor, {
|
||||
actor: did as AtIdentifierString,
|
||||
actor: did,
|
||||
})
|
||||
.then(res => {
|
||||
const dids = res.suggestions
|
||||
@@ -516,7 +516,7 @@ export function useProfileBlockMutationQueue(
|
||||
did,
|
||||
})
|
||||
ax.metric('profile:block', {})
|
||||
return uri
|
||||
return uri as AtUriString
|
||||
} else {
|
||||
if (prevBlockUri) {
|
||||
await unblockMutation.mutateAsync({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {Client} from '@atproto/lex-client'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
|
||||
import {Agent} from '../session/agent'
|
||||
import {com} from '#/lexicons'
|
||||
|
||||
const RQKEY_ROOT = 'service'
|
||||
export const RQKEY = (serviceUrl: string) => [RQKEY_ROOT, serviceUrl]
|
||||
@@ -9,9 +10,12 @@ export function useServiceQuery(serviceUrl: string) {
|
||||
return useQuery({
|
||||
queryKey: RQKEY(serviceUrl),
|
||||
queryFn: async () => {
|
||||
const agent = new Agent(null, {service: serviceUrl})
|
||||
const res = await agent.com.atproto.server.describeServer()
|
||||
return res.data
|
||||
/*
|
||||
* Unauthenticated throwaway client pointed at the candidate service -
|
||||
* describeServer is a public endpoint on the target PDS/entryway.
|
||||
*/
|
||||
const client = new Client({service: serviceUrl})
|
||||
return await client.call(com.atproto.server.describeServer)
|
||||
},
|
||||
enabled: isValidUrl(serviceUrl),
|
||||
})
|
||||
|
||||
@@ -8,6 +8,8 @@ import {getContentLanguages} from '#/state/preferences/languages'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export const DEFAULT_LIMIT = 15
|
||||
|
||||
@@ -36,11 +38,17 @@ export function useGetSuggestedFeedsQuery({enabled}: {enabled?: boolean}) {
|
||||
},
|
||||
)
|
||||
|
||||
/*
|
||||
* TODO(phase4): drop toLex once getSuggestedFeeds migrates off the bridge
|
||||
* agent (intentionally left on the bridge in Phase 3).
|
||||
*/
|
||||
return {
|
||||
feeds: data.feeds.filter(feed => {
|
||||
const isSaved = !!savedFeeds?.find(s => s.value === feed.uri)
|
||||
return !isSaved
|
||||
}),
|
||||
feeds: toLex<app.bsky.feed.defs.GeneratorView[]>(
|
||||
data.feeds.filter(feed => {
|
||||
const isSaved = !!savedFeeds?.find(s => s.value === feed.uri)
|
||||
return !isSaved
|
||||
}),
|
||||
),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -7,6 +7,7 @@ import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export type QueryProps = {
|
||||
category?: string | null
|
||||
@@ -55,7 +56,15 @@ export function useGetSuggestedOnboardingUsersQuery(props: QueryProps) {
|
||||
if (!data.recIdStr) {
|
||||
logger.debug('getSuggestedOnboardingUsers response missing recIdStr')
|
||||
}
|
||||
return {...data, recId: data.recIdStr}
|
||||
/*
|
||||
* TODO(phase4): drop toLex once getSuggestedOnboardingUsers migrates off
|
||||
* the bridge agent (this unspecced endpoint is intentionally left on the
|
||||
* bridge in Phase 3, so it returns old `@atproto/api` view types).
|
||||
*/
|
||||
return toLex<{
|
||||
actors: app.bsky.actor.defs.ProfileView[]
|
||||
recId: string | undefined
|
||||
}>({...data, recId: data.recIdStr})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export type QueryProps = {
|
||||
limit?: number
|
||||
@@ -47,7 +48,15 @@ export function useGetSuggestedUsersForDiscoverQuery(props: QueryProps = {}) {
|
||||
if (!data.recIdStr) {
|
||||
logger.debug('getSuggestedUsersForDiscover response missing recIdStr')
|
||||
}
|
||||
return {...data, recId: data.recIdStr}
|
||||
/*
|
||||
* TODO(phase4): drop toLex once getSuggestedUsersForDiscover migrates off
|
||||
* the bridge agent (this unspecced endpoint is intentionally left on the
|
||||
* bridge in Phase 3, so it returns old `@atproto/api` view types).
|
||||
*/
|
||||
return toLex<{
|
||||
actors: app.bsky.actor.defs.ProfileView[]
|
||||
recId: string | undefined
|
||||
}>({...data, recId: data.recIdStr})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export type QueryProps = {
|
||||
category?: string | null
|
||||
@@ -49,7 +50,14 @@ export function useGetSuggestedUsersForExploreQuery(props: QueryProps = {}) {
|
||||
if (!data.recIdStr) {
|
||||
logger.debug('getSuggestedUsersForExplore response missing recIdStr')
|
||||
}
|
||||
return {...data, recId: data.recIdStr}
|
||||
/*
|
||||
* TODO(phase4): drop toLex once getSuggestedUsersForExplore migrates off
|
||||
* the bridge agent (intentionally left on the bridge in Phase 3).
|
||||
*/
|
||||
return toLex<{
|
||||
actors: app.bsky.actor.defs.ProfileView[]
|
||||
recId: string | undefined
|
||||
}>({...data, recId: data.recIdStr})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export type QueryProps = {
|
||||
category?: string | null
|
||||
@@ -55,7 +56,14 @@ export function useGetSuggestedUsersForSeeMoreQuery(props: QueryProps = {}) {
|
||||
if (!data.recIdStr) {
|
||||
logger.debug('getSuggestedUsersForSeeMore response missing recIdStr')
|
||||
}
|
||||
return {...data, recId: data.recIdStr}
|
||||
/*
|
||||
* TODO(phase4): drop toLex once this unspecced endpoint migrates off the
|
||||
* bridge agent (intentionally left on the bridge in Phase 3).
|
||||
*/
|
||||
return toLex<{
|
||||
actors: app.bsky.actor.defs.ProfileView[]
|
||||
recId: string | undefined
|
||||
}>({...data, recId: data.recIdStr})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import {getContentLanguages} from '#/state/preferences/languages'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export const createOnboardingSuggestedStarterPacksQueryKey = (
|
||||
interests?: string[],
|
||||
@@ -43,7 +45,14 @@ export function useOnboardingSuggestedStarterPacksQuery({
|
||||
},
|
||||
},
|
||||
)
|
||||
return data
|
||||
/*
|
||||
* TODO(phase4): drop toLex once getOnboardingSuggestedStarterPacks
|
||||
* migrates off the bridge agent (intentionally left on the bridge in
|
||||
* Phase 3).
|
||||
*/
|
||||
return toLex<app.bsky.unspecced.getOnboardingSuggestedStarterPacks.$OutputBody>(
|
||||
data,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import {getContentLanguages} from '#/state/preferences/languages'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export const createSuggestedStarterPacksQueryKey = (interests?: string[]) => [
|
||||
'suggested-starter-packs',
|
||||
@@ -43,7 +45,13 @@ export function useSuggestedStarterPacksQuery({
|
||||
},
|
||||
},
|
||||
)
|
||||
return data
|
||||
/*
|
||||
* TODO(phase4): drop toLex once getSuggestedStarterPacks migrates off the
|
||||
* bridge agent (intentionally left on the bridge in Phase 3).
|
||||
*/
|
||||
return toLex<app.bsky.unspecced.getSuggestedStarterPacks.$OutputBody>(
|
||||
data,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {useCallback} from 'react'
|
||||
import {type AtIdentifierString} from '@atproto/syntax'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
@@ -21,7 +20,7 @@ export function useUpdateProfileVerificationCache() {
|
||||
async ({profile}: {profile: bsky.profile.AnyProfileView}) => {
|
||||
try {
|
||||
const updated = await client.call(app.bsky.actor.getProfile, {
|
||||
actor: (profile.did ?? '') as AtIdentifierString,
|
||||
actor: profile.did ?? '',
|
||||
})
|
||||
updateProfileShadow(qc, profile.did, {
|
||||
verification: updated.verification,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import {type AtIdentifierString, type DidString} from '@atproto/lex-client'
|
||||
import {type DatetimeString} from '@atproto/lex-schema'
|
||||
import {type HandleString} from '@atproto/syntax'
|
||||
import {useMutation} from '@tanstack/react-query'
|
||||
|
||||
import {until} from '#/lib/async/until'
|
||||
@@ -24,9 +22,9 @@ export function useVerificationCreateMutation() {
|
||||
}
|
||||
|
||||
const {uri} = await pdsClient.create(app.bsky.graph.verification, {
|
||||
subject: profile.did as DidString,
|
||||
subject: profile.did,
|
||||
createdAt: new Date().toISOString() as DatetimeString,
|
||||
handle: profile.handle as HandleString,
|
||||
handle: profile.handle,
|
||||
displayName: profile.displayName || '',
|
||||
})
|
||||
|
||||
@@ -44,7 +42,7 @@ export function useVerificationCreateMutation() {
|
||||
},
|
||||
() => {
|
||||
return appviewClient.call(app.bsky.actor.getProfile, {
|
||||
actor: (profile.did ?? '') as AtIdentifierString,
|
||||
actor: profile.did ?? '',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {type AtIdentifierString} from '@atproto/lex-client'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {useMutation} from '@tanstack/react-query'
|
||||
|
||||
@@ -51,7 +50,7 @@ export function useVerificationsRemoveMutation() {
|
||||
},
|
||||
() => {
|
||||
return appviewClient.call(app.bsky.actor.getProfile, {
|
||||
actor: (profile.did ?? '') as AtIdentifierString,
|
||||
actor: profile.did ?? '',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Agent} from '@atproto/api'
|
||||
import {Client} from '@atproto/lex-client'
|
||||
|
||||
import {device} from '#/storage'
|
||||
import {BridgeAgent} from './session-core'
|
||||
|
||||
export const BR_LABELER = 'did:plc:ekitcvx7uwnauoqy5oest3hm' // Brazil
|
||||
export const DE_LABELER = 'did:plc:r55ow3tocux5kafs5dq445fy' // Germany
|
||||
@@ -90,9 +90,9 @@ export function configureAdditionalModerationAuthorities() {
|
||||
* static - so both emit identical global `atproto-accept-labelers` headers.
|
||||
*/
|
||||
const appLabelers = Array.from(
|
||||
new Set([...Agent.appLabelers, ...additionalLabelers]),
|
||||
new Set([...BridgeAgent.appLabelers, ...additionalLabelers]),
|
||||
)
|
||||
|
||||
Client.configure({appLabelers: appLabelers as `did:${string}:${string}`[]})
|
||||
Agent.configure({appLabelers})
|
||||
BridgeAgent.configure({appLabelers})
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
useState,
|
||||
useSyncExternalStore,
|
||||
} from 'react'
|
||||
import {type AtpSessionEvent} from '@atproto/api'
|
||||
import {type Client} from '@atproto/lex-client'
|
||||
import {PasswordSession} from '@atproto/lex-password-session'
|
||||
|
||||
@@ -22,6 +21,7 @@ import {emitSessionDropped} from '../events'
|
||||
import {getPublicLexClient, getUnauthenticatedClient} from './clients'
|
||||
import {type Action, getInitialState, reducer, type State} from './reducer'
|
||||
import {
|
||||
type AtpSessionEvent,
|
||||
buildBundle,
|
||||
createSessionBundleAndCreateAccount,
|
||||
createSessionBundleAndLogin,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {type AtpSessionEvent} from '@atproto/api'
|
||||
import {type SessionData} from '@atproto/lex-password-session'
|
||||
|
||||
import {type Schema} from '../persisted'
|
||||
import {type Action, type State} from './reducer'
|
||||
import {type AtpSessionEvent} from './session-core'
|
||||
import {type SessionAccount} from './types'
|
||||
|
||||
type Reducer = (state: State, action: Action) => State
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {Agent, BSKY_LABELER_DID} from '@atproto/api'
|
||||
import {Client} from '@atproto/lex-client'
|
||||
import {api} from '@bsky.app/sdk'
|
||||
|
||||
@@ -6,17 +5,17 @@ import {IS_TEST_USER} from '#/lib/constants'
|
||||
import {com} from '#/lexicons'
|
||||
import {configureAdditionalModerationAuthorities} from './additional-moderation-authorities'
|
||||
import {readLabelers} from './agent-config'
|
||||
import {type SessionBundle} from './session-core'
|
||||
import {BridgeAgent, type SessionBundle} from './session-core'
|
||||
import {type SessionAccount} from './types'
|
||||
|
||||
/*
|
||||
* The Bluesky moderation labeler DID. `BSKY_LABELER_DID` (from '@atproto/api')
|
||||
* and `api.moderation.did` (from '@bsky.app/sdk') are the SAME value -
|
||||
* `did:plc:ar7c4by46qjdydhdevvrndac` - verified at implementation. We keep
|
||||
* using `BSKY_LABELER_DID` for the global appLabelers config and the
|
||||
* per-account filter (matching the old code) and `api.moderation.did` as the
|
||||
* appview client's base labeler (matching `buildAppviewClient`); both resolve
|
||||
* to identical `atproto-accept-labelers` headers.
|
||||
* The Bluesky moderation labeler DID. The old `BSKY_LABELER_DID` (from
|
||||
* '@atproto/api') and `api.moderation.did` (from '@bsky.app/sdk') are the SAME
|
||||
* value - `did:plc:ar7c4by46qjdydhdevvrndac` - verified at implementation. We
|
||||
* use `api.moderation.did` everywhere: the global appLabelers config, the
|
||||
* per-account filter, and the appview client's base labeler (matching
|
||||
* `buildAppviewClient`); all resolve to identical `atproto-accept-labelers`
|
||||
* headers.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -32,7 +31,7 @@ import {type SessionAccount} from './types'
|
||||
*/
|
||||
function configureGlobalAppLabelers(dids: string[]) {
|
||||
Client.configure({appLabelers: dids as `did:${string}:${string}`[]})
|
||||
Agent.configure({appLabelers: dids})
|
||||
BridgeAgent.configure({appLabelers: dids})
|
||||
}
|
||||
|
||||
export function configureModerationForGuest() {
|
||||
@@ -64,7 +63,7 @@ export async function configureModerationForAccount(
|
||||
// The code below is actually relevant to production (and isn't global).
|
||||
const labelerDids = await readLabelers(account.did).catch(_ => {})
|
||||
if (labelerDids) {
|
||||
const perAccount = labelerDids.filter(did => did !== BSKY_LABELER_DID)
|
||||
const perAccount = labelerDids.filter(did => did !== api.moderation.did)
|
||||
/*
|
||||
* Apply the per-account labelers to both live request paths. The appview
|
||||
* client re-asserts the Bluesky moderation labeler as its base because
|
||||
@@ -86,7 +85,7 @@ export async function configureModerationForAccount(
|
||||
}
|
||||
|
||||
function switchToBskyAppLabeler() {
|
||||
configureGlobalAppLabelers([BSKY_LABELER_DID])
|
||||
configureGlobalAppLabelers([api.moderation.did])
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import {type AtpSessionEvent} from '@atproto/api'
|
||||
|
||||
import {unregisterPushToken} from '#/lib/notifications/notifications'
|
||||
import {logger} from '#/lib/notifications/util'
|
||||
import {wrapSessionReducerForLogging} from './logging'
|
||||
import {createPublicSessionBundle} from './session-core'
|
||||
import {type AtpSessionEvent, createPublicSessionBundle} from './session-core'
|
||||
import {type SessionAccount} from './types'
|
||||
import {createTemporaryAgentsAndResume} from './util'
|
||||
|
||||
|
||||
@@ -50,6 +50,16 @@ import {
|
||||
import {type SessionAccount} from './types'
|
||||
import {isSessionExpired} from './util'
|
||||
|
||||
/*
|
||||
* Re-exported so session-layer siblings (index.tsx, reducer.ts, logging.ts,
|
||||
* moderation.ts, additional-moderation-authorities.ts) import the bridge
|
||||
* vocabulary through this whitelisted bridge module rather than from
|
||||
* '@atproto/api' directly. `Agent` is re-exported as `BridgeAgent` for the
|
||||
* labeler-config statics (`Agent.configure`/`Agent.appLabelers`). Dies with
|
||||
* the bridge in Phase 4.
|
||||
*/
|
||||
export {type AtpSessionEvent, Agent as BridgeAgent} from '@atproto/api'
|
||||
|
||||
/**
|
||||
* Whether an access token was issued for a queued (waitlisted) signup rather
|
||||
* than a full session.
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import {createContext, useContext, useMemo, useState} from 'react'
|
||||
import {
|
||||
type AppBskyActorDefs,
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyUnspeccedGetPostThreadV2,
|
||||
type ModerationDecision,
|
||||
} from '@atproto/api'
|
||||
import {type ModerationDecision} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
@@ -18,21 +13,22 @@ import {
|
||||
RQKEY_LINK_ROOT,
|
||||
} from '#/state/queries/resolve-link'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export interface ComposerOptsPostRef {
|
||||
uri: string
|
||||
cid: string
|
||||
text: string
|
||||
langs?: string[]
|
||||
author: AppBskyActorDefs.ProfileViewBasic
|
||||
embed?: AppBskyFeedDefs.PostView['embed']
|
||||
author: app.bsky.actor.defs.ProfileViewBasic
|
||||
embed?: app.bsky.feed.defs.PostView['embed']
|
||||
moderation?: ModerationDecision
|
||||
}
|
||||
|
||||
export type OnPostSuccessData =
|
||||
| {
|
||||
replyToUri?: string
|
||||
posts: AppBskyUnspeccedGetPostThreadV2.ThreadItem[]
|
||||
posts: app.bsky.unspecced.getPostThreadV2.ThreadItem[]
|
||||
}
|
||||
| undefined
|
||||
|
||||
@@ -48,7 +44,7 @@ export interface ComposerOpts {
|
||||
replyTo?: ComposerOptsPostRef
|
||||
onPost?: (postUri: string | undefined) => void
|
||||
onPostSuccess?: (data: OnPostSuccessData) => void
|
||||
quote?: AppBskyFeedDefs.PostView
|
||||
quote?: app.bsky.feed.defs.PostView
|
||||
mention?: string // handle of user to mention
|
||||
text?: string
|
||||
imageUris?: {uri: string; width: number; height: number; altText?: string}[]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {createContext, useCallback, useContext, useMemo, useState} from 'react'
|
||||
import {type AppBskyFeedThreadgate} from '@atproto/api'
|
||||
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
type StateContext = {
|
||||
uris: Set<string>
|
||||
@@ -74,7 +75,7 @@ export function useThreadgateHiddenReplyUrisAPI() {
|
||||
export function useMergedThreadgateHiddenReplies({
|
||||
threadgateRecord,
|
||||
}: {
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
threadgateRecord?: app.bsky.feed.threadgate.Main
|
||||
}) {
|
||||
const {uris, recentlyUnhiddenUris} = useThreadgateHiddenReplyUris()
|
||||
return useMemo(() => {
|
||||
@@ -89,7 +90,7 @@ export function useMergedThreadgateHiddenReplies({
|
||||
export function useMergeThreadgateHiddenReplies() {
|
||||
const {uris, recentlyUnhiddenUris} = useThreadgateHiddenReplyUris()
|
||||
return useCallback(
|
||||
(threadgate?: AppBskyFeedThreadgate.Record) => {
|
||||
(threadgate?: app.bsky.feed.threadgate.Main) => {
|
||||
const set = new Set([...(threadgate?.hiddenReplies || []), ...uris])
|
||||
for (const uri of recentlyUnhiddenUris) {
|
||||
set.delete(uri)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {useEffect, useId, useState} from 'react'
|
||||
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
|
||||
import {Logger} from '#/logger'
|
||||
import {type FeedSourceInfo} from '#/state/queries/feed'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
/**
|
||||
* Separate logger for better debugging
|
||||
@@ -10,7 +11,7 @@ import {type FeedSourceInfo} from '#/state/queries/feed'
|
||||
const logger = Logger.create(Logger.Context.PostSource)
|
||||
|
||||
export type PostSource = {
|
||||
post: AppBskyFeedDefs.FeedViewPost
|
||||
post: app.bsky.feed.defs.FeedViewPost
|
||||
feedSourceInfo?: FeedSourceInfo
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user