diff options
author | Eric Bailey <git@esb.lol> | 2025-02-18 08:54:25 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-18 08:54:25 -0600 |
commit | a51fc8e434b63a3f85accbf1bd29a01397c4b057 (patch) | |
tree | 44be28fc8812c6d4e20f0784be3a558ede9283cb /src/types | |
parent | e2c0f78719a9e576ad18ef0e4657c63a3147efed (diff) | |
download | voidsky-a51fc8e434b63a3f85accbf1bd29a01397c4b057.tar.zst |
`@atproto/api@next` integration (#7344)
* Bump SDK * Use consistent type in profile query * Omit from constraint for profile shadow * Replace isRecord with isValidRecord in QuoteEmbed * Omit type from constraint for old ProfileCard * Omit type from constraint in profile queries where appropriate * Use correct type for update profile mutation * Conslidate and fix check for isValidRecord in Post.tsx * Replace isRecord with isValidRecord in PostThreadItem * Remove redundant cast in PostThreadFollowBtn * Ignore errors in DebugMod screen * Use matching type in ProfileFollows screen * Use matching type in ProfileFollowers screen * Migrate to isValidRecord in PostFeedItem * Use matching type if PostRepostedBy * Omit type from constraint in avatar props * Use matching types in NotificationFeedItem * Todo * Use isValidRecord in NotfyFeedItem * Improve MediaPreview types * Migrate another isValidRecord in NotificationFeedItem * Migrate to isValidView in queries/util * Migrate to isValidRecord in threadgate/util * Fix types in threadgates * Fix up types in starter-packs queries * Todo * Specify exact types in search-posts * Use internal type util to align types * Ditto last * Migrate postgate/index * Specify exact types in post-thread * Use correct type in post-quotes * FIX potential bug in post-thread * Use correct type in post-feed * Add correct type guards to notifications/feed * Migrate a guard in notifications/util * Migrate guard in Wizard/State * [@next] Profile handling, migrate `ProfileCard` (#7347) * Introduce new utils for profiles, migrate old ProfileCard * Rename, reorg * Add parseEmbed utils * Expand AnyProfileView to include chat profile view, update post shadow to reflect this * Cast for perf reasons * Tighten up types now that we have AnyProfileView * Add fastIsType util * Use `assertDid` Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Use util types * Comment * Use fastIsType where no validation was happening before * suggestions (#7382) * suggestions * Revert unneeded changes --------- Co-authored-by: Eric Bailey <git@esb.lol> * Use new util * Rename to dangerousIsType * Convert object shape * Use dangerous util * Use dangerous util * Use dangerous util, we can trust post records * Use dangerous util * Use AnyProfileVIew * Convert object shape * Clean up handling * Patch moderateProfile to accept known profile views, to discuss * Add AnyStarterPackView and related, implement in first usage * Remove validation, fix type, fix ref * Migrate over list-conversations * Clarify intent behind precacheProfile and its unstable query cache * Clean up unstable profile cache * Fix types during label creation in PwiOptOut (#7346) * Tighten types in queries/list * Chat: use correct profile views * Chat: fix log type check * Chat: construct lexically correct shape, even though it's only internal usage * Chat: use correct profile types * Chat: fix type check in logs * Starter: use correct profile types * Starter: use correct profile types * Starter: tighten types to match lex * Any profile type will work in blocked-and-muted * Use dangerous util * Use dangerousIsType * Update new ProfileCard to use AnyProfileView * Use dangerousIsType * Remove outdated todo * Use correct profile type * Use correct profile types * Tighten up types * Use dangerousIsType * Chat: more type fixes * Remove unused file * Add a few utils * Remove unused file * Ignore feedPost.__source * Clean up types, leave validation in critical path * Use dangerousIstype * Use ANyProfileView * Use isValidRecord * Use dangerousIsType * Fix types in ListCard * Fix FeedInterstitials types * Fix types in FeedCard * Fix types in dms ReportDialog * Fix types in SearchablePeopleList * Fix bad type in composer opts * Starter: ok these need to be loose too * Clarify docs Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Less code Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Use package exports Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> * Use package exports * Bump sdk, update $Typed imports * Format * Format * Fix weird TS error * Remove patch * Beter name * It's memo, can validate * Tighten up parseEmbed, dogfood * Bump sdk * Use asPredicate * Loosen types a bit * use asPredicate * Fix types * Use asPredicate * Use asPredicate * Use asPredicate * Clean up upsertProfile types * Use asPredicate * Use Un util * Fix types * Use new AnyProfileView * Use dangerousIsType * Use asPredicate * Use asPredicate * Add fallback content-type to pass typecheck * Clean up upsertProfile types * Align types * Use dangerousIsType * Use dangerousIsType * Use asPredicate * Align types * Convert findLast * Align types * Just ignore type errors and use findLast * Rename atproto -> bsky * Add validate util * Fix type error * Loosen types * Export post * rename atp bsky * Remove unused code * minor changes * Bump deps * Fix types * Tighten back up loose check * Tighten back up loose check * Fix small bug * Update comment * Revert change --------- Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com> Co-authored-by: Matthieu Sieben <matthieu.sieben@gmail.com>
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/bsky/index.ts | 51 | ||||
-rw-r--r-- | src/types/bsky/post.ts | 148 | ||||
-rw-r--r-- | src/types/bsky/profile.ts | 10 | ||||
-rw-r--r-- | src/types/bsky/starterPack.ts | 11 |
4 files changed, 220 insertions, 0 deletions
diff --git a/src/types/bsky/index.ts b/src/types/bsky/index.ts new file mode 100644 index 000000000..d5acbdbb5 --- /dev/null +++ b/src/types/bsky/index.ts @@ -0,0 +1,51 @@ +import {ValidationResult} from '@atproto/lexicon' + +export * as post from '#/types/bsky/post' +export * as profile from '#/types/bsky/profile' +export * as starterPack from '#/types/bsky/starterPack' + +/** + * Fast type checking without full schema validation, for use with data we + * trust, or for non-critical path use cases. Why? Our SDK's `is*` identity + * utils do not assert the type of the entire object, only the `$type` string. + * + * For full validation of the object schema, use the `validate` export from + * this file. + * + * Usage: + * ```ts + * import * as bsky from '#/types/bsky' + * + * if (bsky.dangerousIsType<AppBskyFeedPost.Record>(item, AppBskyFeedPost.isRecord)) { + * // `item` has type `$Typed<AppBskyFeedPost.Record>` here + * } + * ``` + */ +export function dangerousIsType<R extends {$type?: string}>( + record: unknown, + identity: <V>(v: V) => v is V & {$type: NonNullable<R['$type']>}, +): record is R { + return identity(record) +} + +/** + * Fully validates the object schema, which has a performance cost. + * + * For faster checks with data we trust, like that from our app view, use the + * `dangerousIsType` export from this same file. + * + * Usage: + * ```ts + * import * as bsky from '#/types/bsky' + * + * if (bsky.validate(item, AppBskyFeedPost.validateRecord)) { + * // `item` has type `$Typed<AppBskyFeedPost.Record>` here + * } + * ``` + */ +export function validate<R extends {$type?: string}>( + record: unknown, + validator: (v: unknown) => ValidationResult<R>, +): record is R { + return validator(record).success +} diff --git a/src/types/bsky/post.ts b/src/types/bsky/post.ts new file mode 100644 index 000000000..225726f41 --- /dev/null +++ b/src/types/bsky/post.ts @@ -0,0 +1,148 @@ +import { + AppBskyEmbedExternal, + AppBskyEmbedImages, + AppBskyEmbedRecord, + AppBskyEmbedRecordWithMedia, + AppBskyEmbedVideo, + AppBskyFeedDefs, + AppBskyGraphDefs, + AppBskyLabelerDefs, +} from '@atproto/api' + +export type Embed = + | { + type: 'post' + view: AppBskyEmbedRecord.ViewRecord + } + | { + type: 'post_not_found' + view: AppBskyEmbedRecord.ViewNotFound + } + | { + type: 'post_blocked' + view: AppBskyEmbedRecord.ViewBlocked + } + | { + type: 'post_detached' + view: AppBskyEmbedRecord.ViewDetached + } + | { + type: 'feed' + view: AppBskyFeedDefs.GeneratorView + } + | { + type: 'list' + view: AppBskyGraphDefs.ListView + } + | { + type: 'labeler' + view: AppBskyLabelerDefs.LabelerView + } + | { + type: 'starter_pack' + view: AppBskyGraphDefs.StarterPackViewBasic + } + | { + type: 'images' + view: AppBskyEmbedImages.View + } + | { + type: 'link' + view: AppBskyEmbedExternal.View + } + | { + type: 'video' + view: AppBskyEmbedVideo.View + } + | { + type: 'post_with_media' + view: Embed + media: Embed + } + | { + type: 'unknown' + view: null + } + +export type EmbedType<T extends Embed['type']> = Extract<Embed, {type: T}> + +export function parseEmbedRecordView({record}: AppBskyEmbedRecord.View): Embed { + if (AppBskyEmbedRecord.isViewRecord(record)) { + return { + type: 'post', + view: record, + } + } else if (AppBskyEmbedRecord.isViewNotFound(record)) { + return { + type: 'post_not_found', + view: record, + } + } else if (AppBskyEmbedRecord.isViewBlocked(record)) { + return { + type: 'post_blocked', + view: record, + } + } else if (AppBskyEmbedRecord.isViewDetached(record)) { + return { + type: 'post_detached', + view: record, + } + } else if (AppBskyFeedDefs.isGeneratorView(record)) { + return { + type: 'feed', + view: record, + } + } else if (AppBskyGraphDefs.isListView(record)) { + return { + type: 'list', + view: record, + } + } else if (AppBskyLabelerDefs.isLabelerView(record)) { + return { + type: 'labeler', + view: record, + } + } else if (AppBskyGraphDefs.isStarterPackViewBasic(record)) { + return { + type: 'starter_pack', + view: record, + } + } else { + return { + type: 'unknown', + view: null, + } + } +} + +export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed { + if (AppBskyEmbedImages.isView(embed)) { + return { + type: 'images', + view: embed, + } + } else if (AppBskyEmbedExternal.isView(embed)) { + return { + type: 'link', + view: embed, + } + } else if (AppBskyEmbedVideo.isView(embed)) { + return { + type: 'video', + view: embed, + } + } else if (AppBskyEmbedRecord.isView(embed)) { + return parseEmbedRecordView(embed) + } else if (AppBskyEmbedRecordWithMedia.isView(embed)) { + return { + type: 'post_with_media', + view: parseEmbedRecordView(embed.record), + media: parseEmbed(embed.media), + } + } else { + return { + type: 'unknown', + view: null, + } + } +} diff --git a/src/types/bsky/profile.ts b/src/types/bsky/profile.ts new file mode 100644 index 000000000..7449f117e --- /dev/null +++ b/src/types/bsky/profile.ts @@ -0,0 +1,10 @@ +import {AppBskyActorDefs, ChatBskyActorDefs} from '@atproto/api' + +/** + * Matches any profile view exported by our SDK + */ +export type AnyProfileView = + | AppBskyActorDefs.ProfileViewBasic + | AppBskyActorDefs.ProfileView + | AppBskyActorDefs.ProfileViewDetailed + | ChatBskyActorDefs.ProfileViewBasic diff --git a/src/types/bsky/starterPack.ts b/src/types/bsky/starterPack.ts new file mode 100644 index 000000000..0064e16bc --- /dev/null +++ b/src/types/bsky/starterPack.ts @@ -0,0 +1,11 @@ +import {AppBskyGraphDefs} from '@atproto/api' + +export const isBasicView = AppBskyGraphDefs.isStarterPackViewBasic +export const isView = AppBskyGraphDefs.isStarterPackView + +/** + * Matches any starter pack view exported by our SDK + */ +export type AnyStarterPackView = + | AppBskyGraphDefs.StarterPackViewBasic + | AppBskyGraphDefs.StarterPackView |