Fix starter pack navigation from search and explore (#11563)
(cherry picked from commit a0ed2da006)
This commit is contained in:
committed by
Eric Bailey
parent
e0d998af3d
commit
648a6f32e5
@@ -146,10 +146,7 @@ export function StarterPackScreenInner({
|
|||||||
const isValid =
|
const isValid =
|
||||||
starterPack &&
|
starterPack &&
|
||||||
(starterPack.list || starterPack?.creator?.did === currentAccount?.did) &&
|
(starterPack.list || starterPack?.creator?.did === currentAccount?.did) &&
|
||||||
// Cards may precache a synthetic full view while navigating. Its list CID
|
bsky.starterPack.isTrustedView(starterPack) &&
|
||||||
// is intentionally empty until the server response replaces it, so use
|
|
||||||
// the trusted app-view discriminator here instead of strict validation.
|
|
||||||
bsky.isType(app.bsky.graph.defs.starterPackView, starterPack) &&
|
|
||||||
bsky.matches(app.bsky.graph.starterpack, starterPack.record)
|
bsky.matches(app.bsky.graph.starterpack, starterPack.record)
|
||||||
|
|
||||||
if (!did || !starterPack || !isValid || !moderationOpts) {
|
if (!did || !starterPack || !isValid || !moderationOpts) {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import {type app} from '#/lexicons'
|
/* Full schema matching exercises CID validation, so use the real CID parser. */
|
||||||
|
jest.unmock('multiformats/cid')
|
||||||
|
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {
|
import {
|
||||||
type AnyStarterPackView,
|
type AnyStarterPackView,
|
||||||
isBasicView,
|
isBasicView,
|
||||||
|
isTrustedView,
|
||||||
isView,
|
isView,
|
||||||
} from '#/types/bsky/starterPack'
|
} from '#/types/bsky/starterPack'
|
||||||
|
|
||||||
@@ -9,15 +13,21 @@ const now = () => new Date().toISOString()
|
|||||||
|
|
||||||
const creator = {
|
const creator = {
|
||||||
$type: 'app.bsky.actor.defs#profileViewBasic',
|
$type: 'app.bsky.actor.defs#profileViewBasic',
|
||||||
did: 'did:plc:abc',
|
did: 'did:plc:qrllvid7s54k4hnwtqxwetrf',
|
||||||
handle: 'alice.test',
|
handle: 'joshuajfriedman.com',
|
||||||
}
|
}
|
||||||
|
|
||||||
const basicView = {
|
const basicView = {
|
||||||
$type: 'app.bsky.graph.defs#starterPackViewBasic',
|
$type: 'app.bsky.graph.defs#starterPackViewBasic',
|
||||||
uri: 'at://did:plc:abc/app.bsky.graph.starterpack/123',
|
uri: 'at://did:plc:qrllvid7s54k4hnwtqxwetrf/app.bsky.graph.starterpack/3l4poszxde32k',
|
||||||
cid: 'bafypack',
|
cid: 'bafyreiaxduxpwdpjgvve3klfs4flkwjwfqiurszw4o6jvjarpqqmeqwiza',
|
||||||
record: {},
|
record: {
|
||||||
|
$type: 'app.bsky.graph.starterpack',
|
||||||
|
createdAt: '2024-09-22T03:52:03.686Z',
|
||||||
|
feeds: [],
|
||||||
|
list: 'at://did:plc:qrllvid7s54k4hnwtqxwetrf/app.bsky.graph.list/3l4posztwzy2e',
|
||||||
|
name: 'Bluesky for Art History',
|
||||||
|
},
|
||||||
creator,
|
creator,
|
||||||
indexedAt: now(),
|
indexedAt: now(),
|
||||||
}
|
}
|
||||||
@@ -27,6 +37,18 @@ const fullView = {
|
|||||||
$type: 'app.bsky.graph.defs#starterPackView',
|
$type: 'app.bsky.graph.defs#starterPackView',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {$type: _, ...directFullView} = fullView
|
||||||
|
|
||||||
|
const syntheticFullView = {
|
||||||
|
...fullView,
|
||||||
|
list: {
|
||||||
|
uri: 'at://did:plc:abc/app.bsky.graph.list/123',
|
||||||
|
cid: '',
|
||||||
|
name: 'Starter pack',
|
||||||
|
purpose: 'app.bsky.graph.defs#referencelist',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type-level assertions for the view alias: it must accept both the basic and
|
* Type-level assertions for the view alias: it must accept both the basic and
|
||||||
* the full starter pack view. Compile-time only - a failure surfaces as a
|
* the full starter pack view. Compile-time only - a failure surfaces as a
|
||||||
@@ -76,6 +98,23 @@ describe('types/bsky/starterPack guards', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('isTrustedView', () => {
|
||||||
|
it('accepts a direct full view with an omitted $type', () => {
|
||||||
|
expect(isTrustedView(directFullView)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accepts a typed synthetic view with placeholder fields', () => {
|
||||||
|
expect(
|
||||||
|
app.bsky.graph.defs.starterPackView.matches(syntheticFullView),
|
||||||
|
).toBe(false)
|
||||||
|
expect(isTrustedView(syntheticFullView)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects the basic view', () => {
|
||||||
|
expect(isTrustedView(basicView)).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('narrows a view from either world to a readable shape', () => {
|
it('narrows a view from either world to a readable shape', () => {
|
||||||
/*
|
/*
|
||||||
* The `$type` string is world-independent, so one guard narrows values from
|
* The `$type` string is world-independent, so one guard narrows values from
|
||||||
|
|||||||
@@ -25,6 +25,19 @@ export function isView(v: unknown): v is app.bsky.graph.defs.StarterPackView {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts both forms of a full starter pack view used by the app:
|
||||||
|
*
|
||||||
|
* - direct lexicon refs returned by the app view, where `$type` may be omitted
|
||||||
|
* - trusted synthetic cache entries, which carry `$type` but may contain
|
||||||
|
* placeholder fields that do not yet pass full schema validation
|
||||||
|
*/
|
||||||
|
export function isTrustedView(
|
||||||
|
v: unknown,
|
||||||
|
): v is app.bsky.graph.defs.StarterPackView {
|
||||||
|
return isView(v) || app.bsky.graph.defs.starterPackView.matches(v)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches any starter pack view exported by our SDK.
|
* Matches any starter pack view exported by our SDK.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user