Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

NUX API (#5278)

* Set up nux API

* Bump SDK

* Naming

* Imports

authored by

Eric Bailey and committed by
GitHub
ae71f5ce cff7cbb4

+190 -15
+1 -1
package.json
··· 52 52 "open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web" 53 53 }, 54 54 "dependencies": { 55 - "@atproto/api": "0.13.5", 55 + "@atproto/api": "^0.13.7", 56 56 "@bam.tech/react-native-image-resizer": "^3.0.4", 57 57 "@braintree/sanitize-url": "^6.0.2", 58 58 "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
+29
src/state/queries/nuxs/definitions.ts
··· 1 + import zod from 'zod' 2 + 3 + import {BaseNux} from '#/state/queries/nuxs/types' 4 + 5 + export enum Nux { 6 + One = 'one', 7 + Two = 'two', 8 + } 9 + 10 + export const nuxNames = new Set(Object.values(Nux)) 11 + 12 + export type AppNux = 13 + | BaseNux<{ 14 + id: Nux.One 15 + data: { 16 + likes: number 17 + } 18 + }> 19 + | BaseNux<{ 20 + id: Nux.Two 21 + data: undefined 22 + }> 23 + 24 + export const NuxSchemas = { 25 + [Nux.One]: zod.object({ 26 + likes: zod.number(), 27 + }), 28 + [Nux.Two]: undefined, 29 + }
+83
src/state/queries/nuxs/index.ts
··· 1 + import {useMutation, useQueryClient} from '@tanstack/react-query' 2 + 3 + import {AppNux, Nux} from '#/state/queries/nuxs/definitions' 4 + import {parseAppNux, serializeAppNux} from '#/state/queries/nuxs/util' 5 + import { 6 + preferencesQueryKey, 7 + usePreferencesQuery, 8 + } from '#/state/queries/preferences' 9 + import {useAgent} from '#/state/session' 10 + 11 + export {Nux} from '#/state/queries/nuxs/definitions' 12 + 13 + export function useNuxs() { 14 + const {data, ...rest} = usePreferencesQuery() 15 + 16 + if (data && rest.isSuccess) { 17 + const nuxs = data.bskyAppState.nuxs 18 + ?.map(parseAppNux) 19 + ?.filter(Boolean) as AppNux[] 20 + 21 + if (nuxs) { 22 + return { 23 + nuxs, 24 + ...rest, 25 + } 26 + } 27 + } 28 + 29 + return { 30 + nuxs: undefined, 31 + ...rest, 32 + } 33 + } 34 + 35 + export function useNux<T extends Nux>(id: T) { 36 + const {nuxs, ...rest} = useNuxs() 37 + 38 + if (nuxs && rest.isSuccess) { 39 + const nux = nuxs.find(nux => nux.id === id) 40 + 41 + if (nux) { 42 + return { 43 + nux: nux as Extract<AppNux, {id: T}>, 44 + ...rest, 45 + } 46 + } 47 + } 48 + 49 + return { 50 + nux: undefined, 51 + ...rest, 52 + } 53 + } 54 + 55 + export function useUpsertNuxMutation() { 56 + const queryClient = useQueryClient() 57 + const agent = useAgent() 58 + 59 + return useMutation({ 60 + mutationFn: async (nux: AppNux) => { 61 + await agent.bskyAppUpsertNux(serializeAppNux(nux)) 62 + // triggers a refetch 63 + await queryClient.invalidateQueries({ 64 + queryKey: preferencesQueryKey, 65 + }) 66 + }, 67 + }) 68 + } 69 + 70 + export function useRemoveNuxsMutation() { 71 + const queryClient = useQueryClient() 72 + const agent = useAgent() 73 + 74 + return useMutation({ 75 + mutationFn: async (ids: string[]) => { 76 + await agent.bskyAppRemoveNuxs(ids) 77 + // triggers a refetch 78 + await queryClient.invalidateQueries({ 79 + queryKey: preferencesQueryKey, 80 + }) 81 + }, 82 + }) 83 + }
+9
src/state/queries/nuxs/types.ts
··· 1 + import {AppBskyActorDefs} from '@atproto/api' 2 + 3 + export type Data = Record<string, unknown> | undefined 4 + 5 + export type BaseNux< 6 + T extends Pick<AppBskyActorDefs.Nux, 'id' | 'expiresAt'> & {data: Data}, 7 + > = T & { 8 + completed: boolean 9 + }
+52
src/state/queries/nuxs/util.ts
··· 1 + import {AppBskyActorDefs, nuxSchema} from '@atproto/api' 2 + 3 + import { 4 + AppNux, 5 + Nux, 6 + nuxNames, 7 + NuxSchemas, 8 + } from '#/state/queries/nuxs/definitions' 9 + 10 + export function parseAppNux(nux: AppBskyActorDefs.Nux): AppNux | undefined { 11 + if (!nuxNames.has(nux.id as Nux)) return 12 + if (!nuxSchema.safeParse(nux).success) return 13 + 14 + const {data, ...rest} = nux 15 + 16 + const schema = NuxSchemas[nux.id as Nux] 17 + 18 + if (schema && data) { 19 + const parsedData = JSON.parse(data) 20 + 21 + if (!schema.safeParse(parsedData).success) return 22 + 23 + return { 24 + ...rest, 25 + data: parsedData, 26 + } as AppNux 27 + } 28 + 29 + return { 30 + ...rest, 31 + data: undefined, 32 + } as AppNux 33 + } 34 + 35 + export function serializeAppNux(nux: AppNux): AppBskyActorDefs.Nux { 36 + const {data, ...rest} = nux 37 + const schema = NuxSchemas[nux.id as Nux] 38 + 39 + const result: AppBskyActorDefs.Nux = { 40 + ...rest, 41 + data: undefined, 42 + } 43 + 44 + if (schema) { 45 + schema.parse(data) 46 + result.data = JSON.stringify(data) 47 + } 48 + 49 + nuxSchema.parse(result) 50 + 51 + return result 52 + }
+1
src/state/queries/preferences/const.ts
··· 37 37 bskyAppState: { 38 38 queuedNudges: [], 39 39 activeProgressGuide: undefined, 40 + nuxs: [], 40 41 }, 41 42 }
+15 -14
yarn.lock
··· 72 72 resolved "https://registry.yarnpkg.com/@atproto-labs/simple-store/-/simple-store-0.1.1.tgz#e743a2722b5d8732166f0a72aca8bd10e9bff106" 73 73 integrity sha512-WKILW2b3QbAYKh+w5U2x6p5FqqLl0nAeLwGeDY+KjX01K4Dq3vQTR9b/qNp0jZm48CabPQVrqCv0PPU9LgRRRg== 74 74 75 - "@atproto/api@0.13.5": 76 - version "0.13.5" 77 - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.5.tgz#04305cdb0a467ba366305c5e95cebb7ce0d39735" 78 - integrity sha512-yT/YimcKYkrI0d282Zxo7O30OSYR+KDW89f81C6oYZfDRBcShC1aniVV8kluP5LrEAg8O27yrOSnBgx2v7XPew== 75 + "@atproto/api@^0.13.0": 76 + version "0.13.0" 77 + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.0.tgz#d1c65a407f1c3c6aba5be9425f4f739a01419bd8" 78 + integrity sha512-04kzIDkoEVSP7zMVOT5ezCVQcOrbXWjGYO2YBc3/tBvQ90V1pl9I+mLyz1uUHE+wRE1IRWKACcWhAz8SrYz3pA== 79 79 dependencies: 80 80 "@atproto/common-web" "^0.3.0" 81 81 "@atproto/lexicon" "^0.4.1" 82 82 "@atproto/syntax" "^0.3.0" 83 - "@atproto/xrpc" "^0.6.1" 83 + "@atproto/xrpc" "^0.6.0" 84 84 await-lock "^2.2.2" 85 85 multiformats "^9.9.0" 86 86 tlds "^1.234.0" 87 87 88 - "@atproto/api@^0.13.0": 89 - version "0.13.0" 90 - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.0.tgz#d1c65a407f1c3c6aba5be9425f4f739a01419bd8" 91 - integrity sha512-04kzIDkoEVSP7zMVOT5ezCVQcOrbXWjGYO2YBc3/tBvQ90V1pl9I+mLyz1uUHE+wRE1IRWKACcWhAz8SrYz3pA== 88 + "@atproto/api@^0.13.7": 89 + version "0.13.7" 90 + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.7.tgz#072eba2025d5251505f17b0b5d2de33749ea5ee4" 91 + integrity sha512-41kSLmFWDbuPOenb52WRq1lnBkSZrL+X29tWcvEt6SZXK4xBoKAalw1MjF+oabhzff12iMtNaNvmmt2fu1L+cw== 92 92 dependencies: 93 93 "@atproto/common-web" "^0.3.0" 94 94 "@atproto/lexicon" "^0.4.1" 95 95 "@atproto/syntax" "^0.3.0" 96 - "@atproto/xrpc" "^0.6.0" 96 + "@atproto/xrpc" "^0.6.2" 97 97 await-lock "^2.2.2" 98 98 multiformats "^9.9.0" 99 99 tlds "^1.234.0" 100 + zod "^3.23.8" 100 101 101 102 "@atproto/aws@^0.2.2": 102 103 version "0.2.2" ··· 443 444 "@atproto/lexicon" "^0.4.1" 444 445 zod "^3.23.8" 445 446 446 - "@atproto/xrpc@^0.6.1": 447 - version "0.6.1" 448 - resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.1.tgz#dcd1315c8c60eef5af2db7fa4e35a38ebc6d79d5" 449 - integrity sha512-Zy5ydXEdk6sY7FDUZcEVfCL1jvbL4tXu5CcdPqbEaW6LQtk9GLds/DK1bCX9kswTGaBC88EMuqQMfkxOhp2t4A== 447 + "@atproto/xrpc@^0.6.2": 448 + version "0.6.2" 449 + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.2.tgz#634228a7e533de01bda2214837d11574fdadad55" 450 + integrity sha512-as/gb08xJb02HAGNrSQSumCe10WnOAcnM6bR6KMatQyQJuEu7OY6ZDSTM/4HfjjoxsNqdvPmbYuoUab1bKTNlA== 450 451 dependencies: 451 452 "@atproto/lexicon" "^0.4.1" 452 453 zod "^3.23.8"