phase 4 foundations: vendor missing lexicons, refreshSession api, toLex no-op purge, de-agent link-meta
This commit is contained in:
@@ -205,12 +205,8 @@ export function useFeedPreviews(
|
||||
if (item.isFallbackMarker) continue
|
||||
|
||||
const moderations = item.items.map(item =>
|
||||
// TODO(phase4): drop toLex once feed-manip is migrated off
|
||||
// @atproto/api and yields lex-typed slice items.
|
||||
moderatePost(
|
||||
bsky.toLex<app.bsky.feed.defs.PostView>(item.post),
|
||||
moderationOpts!,
|
||||
),
|
||||
moderatePost(item.post, moderationOpts!),
|
||||
)
|
||||
|
||||
// apply moderation filters
|
||||
@@ -236,19 +232,12 @@ export function useFeedPreviews(
|
||||
const feedPostSliceItem: FeedPostSliceItem = {
|
||||
_reactKey: `${item._reactKey}-${i}-${subItem.post.uri}`,
|
||||
uri: subItem.post.uri,
|
||||
// TODO(phase4): drop toLex once feed-manip is migrated
|
||||
// off @atproto/api and yields lex-typed slice items.
|
||||
post: bsky.toLex<app.bsky.feed.defs.PostView>(
|
||||
subItem.post,
|
||||
),
|
||||
record: bsky.toLex<app.bsky.feed.post.Main>(
|
||||
subItem.record,
|
||||
),
|
||||
post: subItem.post,
|
||||
record: subItem.record,
|
||||
moderation: moderations[i],
|
||||
parentAuthor: subItem.parentAuthor
|
||||
? bsky.toLex<app.bsky.actor.defs.ProfileViewBasic>(
|
||||
subItem.parentAuthor,
|
||||
)
|
||||
? subItem.parentAuthor
|
||||
: undefined,
|
||||
isParentBlocked: subItem.isParentBlocked,
|
||||
isParentNotFound: subItem.isParentNotFound,
|
||||
|
||||
@@ -57,33 +57,24 @@ export function useAddGroupMembers(
|
||||
chat.bsky.actor.defs.ProfileViewBasic[]
|
||||
>(listConvoMembersQueryKey(convoId))
|
||||
|
||||
/*
|
||||
* The profile views come from producers that still emit the old
|
||||
* `@atproto/api` shapes (useProfileQuery migrates in a later task), while
|
||||
* the chat caches are now typed on the lexicon views. Structurally
|
||||
* identical modulo branded strings. TODO(phase4): drop toLex once those
|
||||
* producers migrate.
|
||||
*/
|
||||
const addedBy: chat.bsky.actor.defs.ProfileViewBasic | undefined =
|
||||
myProfile
|
||||
? bsky.toLex<chat.bsky.actor.defs.ProfileViewBasic>({
|
||||
? {
|
||||
...myProfile,
|
||||
$type: 'chat.bsky.actor.defs#profileViewBasic',
|
||||
})
|
||||
}
|
||||
: undefined
|
||||
|
||||
const optimisticMembers: chat.bsky.actor.defs.ProfileViewBasic[] =
|
||||
profiles.map(profile =>
|
||||
bsky.toLex<chat.bsky.actor.defs.ProfileViewBasic>({
|
||||
...profile,
|
||||
$type: 'chat.bsky.actor.defs#profileViewBasic',
|
||||
kind: {
|
||||
$type: 'chat.bsky.actor.defs#groupConvoMember',
|
||||
role: 'standard',
|
||||
addedBy,
|
||||
},
|
||||
}),
|
||||
)
|
||||
profiles.map(profile => ({
|
||||
...profile,
|
||||
$type: 'chat.bsky.actor.defs#profileViewBasic',
|
||||
kind: {
|
||||
$type: 'chat.bsky.actor.defs#groupConvoMember',
|
||||
role: 'standard',
|
||||
addedBy,
|
||||
},
|
||||
}))
|
||||
|
||||
queryClient.setQueryData<chat.bsky.convo.defs.ConvoView>(
|
||||
CONVO_KEY(convoId),
|
||||
|
||||
@@ -297,11 +297,8 @@ export function* findAllPostsInQueryData(
|
||||
if (bsky.isType(app.bsky.feed.defs.postView, item.subject)) {
|
||||
const quotedPost = getEmbeddedPost(item.subject?.embed)
|
||||
if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
|
||||
// TODO(phase4): drop toLex once ../util is migrated and
|
||||
// embedViewRecordToPostView returns the lexicon PostView.
|
||||
yield bsky.toLex<app.bsky.feed.defs.PostView>(
|
||||
embedViewRecordToPostView(quotedPost),
|
||||
)
|
||||
yield embedViewRecordToPostView(quotedPost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,9 +288,8 @@ export function usePostFeedQuery(
|
||||
.map(slice => {
|
||||
const moderations = slice.items.map(item =>
|
||||
moderatePost(
|
||||
// TODO(phase4): drop toLex once feed-manip is migrated
|
||||
// off @atproto/api and yields lex-typed slice items.
|
||||
bsky.toLex<app.bsky.feed.defs.PostView>(item.post),
|
||||
item.post,
|
||||
moderationOpts!,
|
||||
),
|
||||
)
|
||||
@@ -342,19 +341,12 @@ export function usePostFeedQuery(
|
||||
const feedPostSliceItem: FeedPostSliceItem = {
|
||||
_reactKey: `${slice._reactKey}-${i}-${item.post.uri}`,
|
||||
uri: item.post.uri,
|
||||
// TODO(phase4): drop toLex once feed-manip is migrated
|
||||
// off @atproto/api and yields lex-typed slice items.
|
||||
post: bsky.toLex<app.bsky.feed.defs.PostView>(
|
||||
item.post,
|
||||
),
|
||||
record: bsky.toLex<app.bsky.feed.post.Main>(
|
||||
item.record,
|
||||
),
|
||||
post: item.post,
|
||||
record: item.record,
|
||||
moderation: moderations[i],
|
||||
parentAuthor: item.parentAuthor
|
||||
? bsky.toLex<app.bsky.actor.defs.ProfileViewBasic>(
|
||||
item.parentAuthor,
|
||||
)
|
||||
? item.parentAuthor
|
||||
: undefined,
|
||||
isParentBlocked: item.isParentBlocked,
|
||||
isParentNotFound: item.isParentNotFound,
|
||||
|
||||
@@ -44,7 +44,6 @@ import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export * from '#/state/queries/preferences/const'
|
||||
export * from '#/state/queries/preferences/moderation'
|
||||
@@ -110,16 +109,8 @@ export function usePreferencesQuery() {
|
||||
) {
|
||||
data = {
|
||||
...data,
|
||||
/*
|
||||
* TODO(phase4): drop the toLex bridges once
|
||||
* `#/ageAssurance/util` (makeAgeRestrictedModerationPrefs) sources
|
||||
* `ModerationPrefs` from `@bsky.app/sdk/moderation` instead of
|
||||
* `@atproto/api`. The two shapes differ only in scalar branding
|
||||
* (e.g. MutedWord.actorTarget's UnknownString), so the values are
|
||||
* structurally interchangeable at this boundary.
|
||||
*/
|
||||
moderationPrefs: toLex(
|
||||
makeAgeRestrictedModerationPrefs(toLex(data.moderationPrefs)),
|
||||
moderationPrefs: makeAgeRestrictedModerationPrefs(
|
||||
data.moderationPrefs,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
resolveLink,
|
||||
} from '#/lib/api/resolve'
|
||||
import {STALE} from '#/state/queries/index'
|
||||
import {useAgent, useChatClient, useLexClient} from '#/state/session'
|
||||
import {useChatClient, useLexClient} from '#/state/session'
|
||||
import {type Gif} from '#/features/gifPicker/types'
|
||||
|
||||
export const RQKEY_LINK_ROOT = 'resolve-link'
|
||||
@@ -26,15 +26,13 @@ export function resolveLinkQueryOptions(clients: ResolveClients, url: string) {
|
||||
|
||||
/**
|
||||
* Bundle the clients the link resolver needs from the session hooks. The
|
||||
* appview client serves the `app.bsky.*` reads and handle resolution, the chat
|
||||
* client serves group join-link previews, and the bridge agent is still passed
|
||||
* through to the not-yet-migrated `getLinkMeta`.
|
||||
* appview client serves the `app.bsky.*` reads and handle resolution, and the
|
||||
* chat client serves group join-link previews.
|
||||
*/
|
||||
export function useResolveClients(): ResolveClients {
|
||||
const appview = useLexClient()
|
||||
const chat = useChatClient()
|
||||
const agent = useAgent()
|
||||
return {appview, chat, agent}
|
||||
return {appview, chat}
|
||||
}
|
||||
|
||||
export function useResolveLinkQuery(url: string) {
|
||||
|
||||
@@ -255,27 +255,23 @@ export function* getThreadPlaceholderCandidates(
|
||||
for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) {
|
||||
yield postViewToThreadPlaceholder(post)
|
||||
}
|
||||
/*
|
||||
* TODO(phase4): drop toLex once the feed/quote/search/bookmarks/explore
|
||||
* `findAllPostsInQueryData` generators are migrated to `#/lexicons` types.
|
||||
*/
|
||||
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {
|
||||
yield postViewToThreadPlaceholder(bsky.toLex(post))
|
||||
yield postViewToThreadPlaceholder(post)
|
||||
}
|
||||
for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
|
||||
yield postViewToThreadPlaceholder(bsky.toLex(post))
|
||||
yield postViewToThreadPlaceholder(post)
|
||||
}
|
||||
for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
|
||||
yield postViewToThreadPlaceholder(bsky.toLex(post))
|
||||
yield postViewToThreadPlaceholder(post)
|
||||
}
|
||||
for (let post of findAllPostsInBookmarksQueryData(queryClient, uri)) {
|
||||
yield postViewToThreadPlaceholder(bsky.toLex(post))
|
||||
yield postViewToThreadPlaceholder(post)
|
||||
}
|
||||
for (let post of findAllPostsInExploreFeedPreviewsQueryData(
|
||||
queryClient,
|
||||
uri,
|
||||
)) {
|
||||
yield postViewToThreadPlaceholder(bsky.toLex(post))
|
||||
yield postViewToThreadPlaceholder(post)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,11 +298,7 @@ export function* findAllPostsInQueryData(
|
||||
|
||||
const qp = getEmbeddedPost(item.value.post.embed)
|
||||
if (qp && didOrHandleUriMatches(atUri, qp)) {
|
||||
/*
|
||||
* TODO(phase4): drop toLex once `embedViewRecordToPostView` in
|
||||
* `#/state/queries/util` is migrated to `#/lexicons` types.
|
||||
*/
|
||||
yield bsky.toLex(embedViewRecordToPostView(qp))
|
||||
yield embedViewRecordToPostView(qp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,11 +327,7 @@ export function* findAllProfilesInQueryData(
|
||||
|
||||
const qp = getEmbeddedPost(item.value.post.embed)
|
||||
if (qp && qp.author.did === did) {
|
||||
/*
|
||||
* TODO(phase4): drop toLex once `getEmbeddedPost` in
|
||||
* `#/state/queries/util` is migrated to `#/lexicons` types.
|
||||
*/
|
||||
yield bsky.toLex(qp.author)
|
||||
yield qp.author
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ const ApiContext = createContext<SessionApiContext>({
|
||||
resumeSession: async () => {},
|
||||
removeAccount: () => {},
|
||||
partialRefreshSession: async () => {},
|
||||
refreshSession: () => Promise.resolve(undefined),
|
||||
})
|
||||
ApiContext.displayName = 'SessionApiContext'
|
||||
|
||||
@@ -344,6 +345,28 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
})
|
||||
}, [store, state, cancelPendingTask])
|
||||
|
||||
const refreshSession = useCallback<
|
||||
SessionApiContext['refreshSession']
|
||||
>(async () => {
|
||||
const bundle = store.getState().currentAgentState.agent as unknown as
|
||||
| SessionBundle
|
||||
| PublicSessionBundle
|
||||
if (!bundle.session) return undefined // logged out: nothing to refresh
|
||||
/*
|
||||
* PasswordSession.refresh() re-runs com.atproto.server.refreshSession +
|
||||
* getSession. On success the session's onUpdated hook fires, which the
|
||||
* armed makeSessionHooks wiring maps to an 'update' event; the reducer
|
||||
* snapshots the refreshed account. No explicit dispatch is needed here.
|
||||
* The returned snapshot lets callers read post-refresh fields without
|
||||
* waiting on the (async) reducer update.
|
||||
*/
|
||||
await bundle.session.refresh()
|
||||
return sessionDataToSessionAccount(
|
||||
bundle.session.session,
|
||||
bundle.session.session.service,
|
||||
)
|
||||
}, [store])
|
||||
|
||||
const removeAccount = useCallback<SessionApiContext['removeAccount']>(
|
||||
account => {
|
||||
addSessionDebugLog({
|
||||
@@ -443,6 +466,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
resumeSession,
|
||||
removeAccount,
|
||||
partialRefreshSession,
|
||||
refreshSession,
|
||||
}),
|
||||
[
|
||||
createAccount,
|
||||
@@ -452,6 +476,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
resumeSession,
|
||||
removeAccount,
|
||||
partialRefreshSession,
|
||||
refreshSession,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -51,4 +51,15 @@ export type SessionApiContext = {
|
||||
* `persistSessionHandler`.
|
||||
*/
|
||||
partialRefreshSession: () => Promise<void>
|
||||
/**
|
||||
* Force a full session refresh (re-runs `com.atproto.server.refreshSession`
|
||||
* plus `getSession`) and return the refreshed account snapshot, or
|
||||
* `undefined` when logged out.
|
||||
*
|
||||
* The refresh routes through the session's own `refresh()`, whose success
|
||||
* hook propagates the updated account into state; the returned snapshot lets
|
||||
* callers read post-refresh fields synchronously without waiting on the
|
||||
* (async) reducer update. Rejections propagate to the caller.
|
||||
*/
|
||||
refreshSession: () => Promise<SessionAccount | undefined>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user