phase 4 foundations: vendor missing lexicons, refreshSession api, toLex no-op purge, de-agent link-meta
This commit is contained in:
@@ -2,7 +2,6 @@ import {type Client} from '@atproto/lex-client'
|
||||
|
||||
import {DEMO_FEED} from '#/lib/demo'
|
||||
import {type app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
import {type FeedAPI, type FeedAPIResponse} from './types'
|
||||
|
||||
export class DemoFeedAPI implements FeedAPI {
|
||||
@@ -12,17 +11,13 @@ export class DemoFeedAPI implements FeedAPI {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async peekLatest(): Promise<app.bsky.feed.defs.FeedViewPost> {
|
||||
/*
|
||||
* TODO(phase4): drop this cast once `#/lib/demo` (DEMO_FEED) sources its
|
||||
* feed items from `#/lexicons`. Its records are still typed against the old
|
||||
* `@atproto/api` FeedViewPost, which does not assign to the branded lexicon
|
||||
* type this method must return.
|
||||
*/
|
||||
return toLex(DEMO_FEED.feed[0])
|
||||
return DEMO_FEED.feed[0]
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async fetch(): Promise<FeedAPIResponse> {
|
||||
return toLex(DEMO_FEED)
|
||||
return DEMO_FEED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import {feedUriToHref} from '#/lib/strings/url-helpers'
|
||||
import {getContentLanguages} from '#/state/preferences/languages'
|
||||
import {type FeedParams} from '#/state/queries/post-feed'
|
||||
import {app} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
import {FeedTuner} from '../feed-manip'
|
||||
import {type FeedTunerFn} from '../feed-manip'
|
||||
import {
|
||||
@@ -264,13 +263,7 @@ class MergeFeedSource_Following extends MergeFeedSource {
|
||||
return {
|
||||
success: true,
|
||||
cursor: res.cursor,
|
||||
/*
|
||||
* TODO(phase4): drop the toLex once `#/lib/api/feed-manip` (FeedTuner)
|
||||
* flips its FeedViewPost source from `@atproto/api` to `#/lexicons`. Its
|
||||
* `_feedPost` is still the old-world view type, which does not assign to
|
||||
* the branded lexicon type this page carries.
|
||||
*/
|
||||
feed: slices.map(slice => toLex(slice._feedPost)),
|
||||
feed: slices.map(slice => slice._feedPost),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-35
@@ -91,16 +91,7 @@ export async function post(
|
||||
for (let i = 0; i < thread.posts.length; i++) {
|
||||
const draft = thread.posts[i]
|
||||
|
||||
/*
|
||||
* Not awaited to avoid waterfalls. `draft.richtext` is still an
|
||||
* `@atproto/api` RichText (composer state is migrated by Task 7); the SDK
|
||||
* RichText is structurally the same transplant, so bridge it here.
|
||||
* TODO(phase4): drop toLex once composer state migrates to SDK RichText.
|
||||
*/
|
||||
const rtPromise = resolveRT(
|
||||
resolveClients.appview,
|
||||
bsky.toLex<RichText>(draft.richtext),
|
||||
)
|
||||
const rtPromise = resolveRT(resolveClients.appview, draft.richtext)
|
||||
const embedPromise = resolveEmbed(
|
||||
clients,
|
||||
queryClient,
|
||||
@@ -138,17 +129,11 @@ export async function post(
|
||||
langs,
|
||||
labels,
|
||||
}
|
||||
/*
|
||||
* `value` is typed `LexMap` (a loose index-signature map). A generated
|
||||
* record type is a valid LexMap at runtime but a strict interface is not
|
||||
* assignable to an index-signature type, so widen with `toLex` at this
|
||||
* boundary. Not a brand cast - the record is already fully typed.
|
||||
*/
|
||||
writes.push({
|
||||
$type: 'com.atproto.repo.applyWrites#create',
|
||||
collection: 'app.bsky.feed.post',
|
||||
rkey: rkey,
|
||||
value: bsky.toLex(record),
|
||||
value: record,
|
||||
})
|
||||
|
||||
if (i === 0 && thread.threadgate.some(tg => tg.type !== 'everybody')) {
|
||||
@@ -156,14 +141,10 @@ export async function post(
|
||||
$type: 'com.atproto.repo.applyWrites#create',
|
||||
collection: 'app.bsky.feed.threadgate',
|
||||
rkey: rkey,
|
||||
value: bsky.toLex(
|
||||
createThreadgateRecord({
|
||||
post: uri,
|
||||
allow: threadgateAllowUISettingToAllowRecordValue(
|
||||
thread.threadgate,
|
||||
),
|
||||
}),
|
||||
),
|
||||
value: createThreadgateRecord({
|
||||
post: uri,
|
||||
allow: threadgateAllowUISettingToAllowRecordValue(thread.threadgate),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -175,12 +156,12 @@ export async function post(
|
||||
$type: 'com.atproto.repo.applyWrites#create',
|
||||
collection: 'app.bsky.feed.postgate',
|
||||
rkey: rkey,
|
||||
value: bsky.toLex({
|
||||
value: {
|
||||
...thread.postgate,
|
||||
$type: 'app.bsky.feed.postgate',
|
||||
createdAt: now.toISOString(),
|
||||
post: uri,
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -426,7 +407,7 @@ async function resolveMedia(
|
||||
* structural shape matches the lexicon blob field; the CID hasher handles
|
||||
* both class instances and plain lex blobs (see computeCid).
|
||||
*/
|
||||
video: bsky.toLex(videoDraft.pendingPublish.blobRef),
|
||||
video: videoDraft.pendingPublish.blobRef,
|
||||
alt: videoDraft.altText || undefined,
|
||||
captions: captions.length === 0 ? undefined : captions,
|
||||
aspectRatio,
|
||||
@@ -475,13 +456,7 @@ async function resolveMedia(
|
||||
title: resolvedLink.title,
|
||||
description: resolvedLink.description,
|
||||
thumb: blob,
|
||||
/*
|
||||
* associatedRefs comes from getLinkMeta, still typed with the old
|
||||
* `@atproto/api` StrongRef (link-meta.ts is out of scope). The shape
|
||||
* is identical; bridge with toLex.
|
||||
* TODO(phase4): drop toLex once link-meta migrates.
|
||||
*/
|
||||
associatedRefs: bsky.toLex(resolvedLink.associatedRefs),
|
||||
associatedRefs: resolvedLink.associatedRefs,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+3
-15
@@ -23,7 +23,6 @@ import {
|
||||
import {type ComposerImage} from '#/state/gallery'
|
||||
import {createComposerImage} from '#/state/gallery'
|
||||
import {type ChatInvitePreview} from '#/state/queries/join-links'
|
||||
import {type SessionAgent} from '#/state/session'
|
||||
import {type Gif} from '#/features/gifPicker/types'
|
||||
import {app, chat, com} from '#/lexicons'
|
||||
import {createGIFDescription} from '../gif-alt-text'
|
||||
@@ -31,13 +30,10 @@ import {createGIFDescription} from '../gif-alt-text'
|
||||
/**
|
||||
* Clients the link resolver needs. `appview` serves the `app.bsky.*` feed/graph
|
||||
* reads plus handle resolution; `chat` serves the group join-link previews.
|
||||
* `agent` is still threaded through to {@link getLinkMeta}, which has not yet
|
||||
* migrated off the bridge - it only reads the (unused) service URL from it.
|
||||
*/
|
||||
export type ResolveClients = {
|
||||
appview: Client
|
||||
chat: Client
|
||||
agent: SessionAgent
|
||||
}
|
||||
|
||||
type ResolvedExternalLink = {
|
||||
@@ -195,7 +191,7 @@ export async function resolveLink(
|
||||
view: res.starterPack,
|
||||
}
|
||||
}
|
||||
return resolveExternal(clients, uri)
|
||||
return resolveExternal(uri)
|
||||
|
||||
// Forked from useGetPost. TODO: move into RQ.
|
||||
async function getPost({uri}: {uri: string}) {
|
||||
@@ -267,16 +263,8 @@ function getFileSlug(url: string | undefined): string | undefined {
|
||||
return dotIndex > 0 ? filename.slice(0, dotIndex) : undefined
|
||||
}
|
||||
|
||||
async function resolveExternal(
|
||||
clients: ResolveClients,
|
||||
uri: string,
|
||||
): Promise<ResolvedExternalLink> {
|
||||
/*
|
||||
* getLinkMeta still takes the bridge agent (not yet migrated); it only reads
|
||||
* a service URL from it that LINK_META_PROXY ignores. Keep threading the
|
||||
* agent here until link-meta migrates.
|
||||
*/
|
||||
const result = await getLinkMeta(clients.agent, uri)
|
||||
async function resolveExternal(uri: string): Promise<ResolvedExternalLink> {
|
||||
const result = await getLinkMeta(uri)
|
||||
return {
|
||||
type: 'external',
|
||||
uri: result.url,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {LINK_META_PROXY} from '#/lib/constants'
|
||||
import {getGiphyMetaUri} from '#/lib/strings/embed-player'
|
||||
import {parseStarterPackUri} from '#/lib/strings/starter-pack'
|
||||
import {type SessionAgent} from '#/state/session'
|
||||
import {type app} from '#/lexicons'
|
||||
import {isBskyAppUrl} from '../strings/url-helpers'
|
||||
|
||||
@@ -31,7 +30,6 @@ export interface LinkMeta {
|
||||
}
|
||||
|
||||
export async function getLinkMeta(
|
||||
agent: SessionAgent,
|
||||
url: string,
|
||||
timeout = 15e3,
|
||||
): Promise<LinkMeta> {
|
||||
@@ -80,9 +78,7 @@ export async function getLinkMeta(
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${LINK_META_PROXY(agent.serviceUrl.toString() || '')}${encodeURIComponent(
|
||||
url,
|
||||
)}`,
|
||||
`${LINK_META_PROXY('')}${encodeURIComponent(url)}`,
|
||||
{signal: controller.signal},
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
} from '#/lib/moderation/useGlobalLabelStrings'
|
||||
import {useLabelDefinitions} from '#/state/preferences'
|
||||
import {type app, type com} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
|
||||
export interface LabelInfo {
|
||||
label: com.atproto.label.defs.Label
|
||||
@@ -23,26 +22,14 @@ export interface LabelInfo {
|
||||
|
||||
export function useLabelInfo(label: com.atproto.label.defs.Label): LabelInfo {
|
||||
const {i18n} = useLingui()
|
||||
/*
|
||||
* TODO(phase4): drop the `toLex` casts once `useLabelDefinitions`
|
||||
* (state/preferences/label-defs) emits `#/lexicons` / `@bsky.app/sdk`
|
||||
* moderation types. It still returns old `@atproto/api`
|
||||
* `InterpretedLabelValueDefinition` / `LabelerViewDetailed`, which are
|
||||
* structurally identical to the SDK/lexicon ones modulo branded strings.
|
||||
*/
|
||||
const {labelDefs, labelers} = useLabelDefinitions()
|
||||
const def = getDefinition(
|
||||
toLex<Record<string, InterpretedLabelValueDefinition[]>>(labelDefs),
|
||||
label,
|
||||
)
|
||||
const def = getDefinition(labelDefs, label)
|
||||
const globalLabelStrings = useGlobalLabelStrings()
|
||||
return {
|
||||
label,
|
||||
def,
|
||||
strings: getLabelStrings(i18n.locale, globalLabelStrings, def),
|
||||
labeler: toLex<app.bsky.labeler.defs.LabelerViewDetailed[]>(labelers).find(
|
||||
labeler => label.src === labeler.creator.did,
|
||||
),
|
||||
labeler: labelers.find(labeler => label.src === labeler.creator.did),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@ import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
|
||||
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
|
||||
import {type AppModerationCause} from '#/components/Pills'
|
||||
import {type com} from '#/lexicons'
|
||||
import {toLex} from '#/types/bsky'
|
||||
import {useGlobalLabelStrings} from './useGlobalLabelStrings'
|
||||
import {getDefinition, getLabelStrings} from './useLabelInfo'
|
||||
|
||||
@@ -129,18 +127,7 @@ export function useModerationCauseDescription(
|
||||
}
|
||||
}
|
||||
if (cause.type === 'label') {
|
||||
/*
|
||||
* TODO(phase4): drop `toLex` once `useLabelDefinitions` and the label
|
||||
* cause type share the `#/lexicons` label shape. `labelDefs` still comes
|
||||
* from the old `@atproto/api`-typed producer and `cause.label` is the SDK
|
||||
* label; both are structurally identical to the `#/lexicons` label.
|
||||
*/
|
||||
const def =
|
||||
cause.labelDef ||
|
||||
getDefinition(
|
||||
toLex<Parameters<typeof getDefinition>[0]>(labelDefs),
|
||||
toLex<com.atproto.label.defs.Label>(cause.label),
|
||||
)
|
||||
const def = cause.labelDef || getDefinition(labelDefs, cause.label)
|
||||
const strings = getLabelStrings(i18n.locale, globalLabelStrings, def)
|
||||
const labeler = labelers.find(l => l.creator.did === cause.label.src)
|
||||
let source = labeler
|
||||
|
||||
Reference in New Issue
Block a user