From 546c34b1cf8c42ea221ffddd88c052bd59e91c62 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 4 Sep 2026 12:58:00 -0500 Subject: [PATCH] Pass interests update time in topics header --- package.json | 2 +- pnpm-lock.yaml | 10 ++--- src/lib/api/feed/__tests__/utils.test.ts | 50 ++++++++++++++++++++++ src/lib/api/feed/utils.ts | 6 ++- src/screens/Settings/InterestsSettings.tsx | 9 +--- 5 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 src/lib/api/feed/__tests__/utils.test.ts diff --git a/package.json b/package.json index 1ac7f45e11..20d2ea850c 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "@bsky.app/tapper": "^0.6.1", "@bsky.app/video": "0.3.6", "@bsky.app/video-compressor": "0.2.0", - "@bsky/sdk": "1.0.1", + "@bsky/sdk": "1.1.2", "@emoji-mart/data": "^1.2.1", "@emoji-mart/react": "^1.1.1", "@expo/html-elements": "^0.12.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9af9df2865..3815e3f2e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -297,8 +297,8 @@ importers: specifier: 0.2.0 version: 0.2.0(expo@57.0.8)(react-native@0.86.0(patch_hash=dd549527bb84c88acc7b0b1d521c9f4b666fda484c75cd0b282f8e9838524909)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1))(react@19.2.3) '@bsky/sdk': - specifier: 1.0.1 - version: 1.0.1(@atproto/lex@0.3.8) + specifier: 1.1.2 + version: 1.1.2(@atproto/lex@0.3.8) '@emoji-mart/data': specifier: ^1.2.1 version: 1.2.1 @@ -1750,8 +1750,8 @@ packages: react: '*' react-native: '*' - '@bsky/sdk@1.0.1': - resolution: {integrity: sha512-COhrmIZFsUJ1gj4gvqm2UWkRhTbmXZAL1osTZKgSaFftD4Xy0RRl8S9SRluCxo4/VPw/R3p7NQZ4X3BQFbUjVQ==} + '@bsky/sdk@1.1.2': + resolution: {integrity: sha512-wMZXVdxnSHViyVrqm+eOpJLZAwfuWLX8gvuCEyV++4k/E/gp9inxQevzuNyCFZv/XJAZ4xRh1WXN7kymF4UMXA==} engines: {node: '>=22.12.0'} peerDependencies: '@atproto/lex': ^0.3.0 @@ -10770,7 +10770,7 @@ snapshots: react: 19.2.3 react-native: 0.86.0(patch_hash=dd549527bb84c88acc7b0b1d521c9f4b666fda484c75cd0b282f8e9838524909)(@babel/core@7.29.0(supports-color@8.1.1))(@react-native/jest-preset@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(react@19.2.3)(supports-color@8.1.1))(@react-native/metro-config@0.86.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@19.2.18)(react@19.2.3)(supports-color@8.1.1) - '@bsky/sdk@1.0.1(@atproto/lex@0.3.8)': + '@bsky/sdk@1.1.2(@atproto/lex@0.3.8)': dependencies: '@atproto-labs/handle-resolver': 0.4.8 '@atproto/lex': 0.3.8 diff --git a/src/lib/api/feed/__tests__/utils.test.ts b/src/lib/api/feed/__tests__/utils.test.ts new file mode 100644 index 0000000000..7863104ea9 --- /dev/null +++ b/src/lib/api/feed/__tests__/utils.test.ts @@ -0,0 +1,50 @@ +import {describe, expect, it, jest} from '@jest/globals' + +import {type UsePreferencesQueryResponse} from '#/state/queries/preferences' + +jest.mock('#/env', () => ({IS_WEB: false})) + +import {aggregateUserInterests, createBskyTopicsHeader} from '../utils' + +function preferences( + interests: Pick< + UsePreferencesQueryResponse['interests'], + 'tags' | 'updatedAt' + >, +) { + return {interests} as UsePreferencesQueryResponse +} + +describe('aggregateUserInterests', () => { + it('appends the update timestamp after a semicolon', () => { + expect( + createBskyTopicsHeader( + aggregateUserInterests( + preferences({ + tags: ['animals', 'music'], + updatedAt: '2026-09-03T17:00:00.000Z', + }), + ), + ), + ).toEqual({ + 'x-atproto-bsky-topics': 'animals,music;2026-09-03T17:00:00.000Z', + }) + }) + + it('supports interests created before update timestamps were recorded', () => { + expect(aggregateUserInterests(preferences({tags: ['animals']}))).toBe( + 'animals', + ) + }) + + it('passes the timestamp when the user has no selected interests', () => { + expect( + aggregateUserInterests( + preferences({ + tags: [], + updatedAt: '2026-09-03T17:00:00.000Z', + }), + ), + ).toBe(';2026-09-03T17:00:00.000Z') + }) +}) diff --git a/src/lib/api/feed/utils.ts b/src/lib/api/feed/utils.ts index 29bca09fc3..8cca3d5715 100644 --- a/src/lib/api/feed/utils.ts +++ b/src/lib/api/feed/utils.ts @@ -19,7 +19,11 @@ export function createBskyTopicsHeader(userInterests?: string) { export function aggregateUserInterests( preferences?: UsePreferencesQueryResponse, ) { - return preferences?.interests?.tags?.join(',') || '' + const tags = preferences?.interests.tags ?? [] + const updatedAt = preferences?.interests.updatedAt + + const interests = tags.join(',') + return updatedAt ? `${interests};${updatedAt}` : interests } export function isBlueskyOwnedFeed(feedUri: string) { diff --git a/src/screens/Settings/InterestsSettings.tsx b/src/screens/Settings/InterestsSettings.tsx index 84589d7481..f92fe458a8 100644 --- a/src/screens/Settings/InterestsSettings.tsx +++ b/src/screens/Settings/InterestsSettings.tsx @@ -112,14 +112,7 @@ function Inner({ try { await pdsClient.call(setInterestsPref, {tags: interests}) - qc.setQueriesData( - {queryKey: preferencesQueryKey}, - (old?: UsePreferencesQueryResponse) => { - if (!old) return old - old.interests.tags = interests - return old - }, - ) + await qc.invalidateQueries({queryKey: preferencesQueryKey}) await Promise.all([ qc.resetQueries({queryKey: createSuggestedStarterPacksQueryKey()}), qc.resetQueries({queryKey: createGetSuggestedFeedsQueryKey()}),