Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Bump API SDK, add validation to MutedWords (#3055)

* Bump API SDK, add validation to MutedWords

* Tweaks to error state

* Comment

* Early return

authored by

Eric Bailey and committed by
GitHub
cecb6e4e 21bdddcf

+89 -24
+1 -1
package.json
··· 44 44 "update-extensions": "scripts/updateExtensions.sh" 45 45 }, 46 46 "dependencies": { 47 - "@atproto/api": "^0.10.0", 47 + "@atproto/api": "^0.10.3", 48 48 "@bam.tech/react-native-image-resizer": "^3.0.4", 49 49 "@braintree/sanitize-url": "^6.0.2", 50 50 "@emoji-mart/react": "^1.1.1",
+2 -4
src/components/TagMenu/index.tsx
··· 215 215 if (isMuted) { 216 216 resetUpsert() 217 217 removeMutedWord({ 218 - value: sanitizedTag, 218 + value: tag, 219 219 targets: ['tag'], 220 220 }) 221 221 } else { 222 222 resetRemove() 223 - upsertMutedWord([ 224 - {value: sanitizedTag, targets: ['tag']}, 225 - ]) 223 + upsertMutedWord([{value: tag, targets: ['tag']}]) 226 224 } 227 225 }) 228 226 }}>
+2 -3
src/components/TagMenu/index.web.tsx
··· 104 104 : _(msg`Mute ${truncatedTag}`), 105 105 onPress() { 106 106 if (isMuted) { 107 - removeMutedWord({value: sanitizedTag, targets: ['tag']}) 107 + removeMutedWord({value: tag, targets: ['tag']}) 108 108 } else { 109 - upsertMutedWord([{value: sanitizedTag, targets: ['tag']}]) 109 + upsertMutedWord([{value: tag, targets: ['tag']}]) 110 110 } 111 111 }, 112 112 testID: 'tagMenuMute', ··· 127 127 preferences, 128 128 tag, 129 129 truncatedTag, 130 - sanitizedTag, 131 130 upsertMutedWord, 132 131 removeMutedWord, 133 132 ])
+51 -9
src/components/dialogs/MutedWords.tsx
··· 2 2 import {View} from 'react-native' 3 3 import {msg, Trans} from '@lingui/macro' 4 4 import {useLingui} from '@lingui/react' 5 - import {AppBskyActorDefs} from '@atproto/api' 5 + import {AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api' 6 6 7 7 import { 8 8 usePreferencesQuery, ··· 10 10 useRemoveMutedWordMutation, 11 11 } from '#/state/queries/preferences' 12 12 import {isNative} from '#/platform/detection' 13 - import {atoms as a, useTheme, useBreakpoints, ViewStyleProp, web} from '#/alf' 13 + import { 14 + atoms as a, 15 + useTheme, 16 + useBreakpoints, 17 + ViewStyleProp, 18 + web, 19 + native, 20 + } from '#/alf' 14 21 import {Text} from '#/components/Typography' 15 22 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 16 23 import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' ··· 48 55 const {isPending, mutateAsync: addMutedWord} = useUpsertMutedWordsMutation() 49 56 const [field, setField] = React.useState('') 50 57 const [options, setOptions] = React.useState(['content']) 51 - const [_error, setError] = React.useState('') 58 + const [error, setError] = React.useState('') 52 59 53 60 const submit = React.useCallback(async () => { 54 - const value = field.trim() 61 + const sanitizedValue = sanitizeMutedWordValue(field) 55 62 const targets = ['tag', options.includes('content') && 'content'].filter( 56 63 Boolean, 57 64 ) as AppBskyActorDefs.MutedWord['targets'] 58 65 59 - if (!value || !targets.length) return 66 + if (!sanitizedValue || !targets.length) { 67 + setField('') 68 + setError(_(msg`Please enter a valid word, tag, or phrase to mute`)) 69 + return 70 + } 60 71 61 72 try { 62 - await addMutedWord([{value, targets}]) 73 + // send raw value and rely on SDK as sanitization source of truth 74 + await addMutedWord([{value: field, targets}]) 63 75 setField('') 64 76 } catch (e: any) { 65 77 logger.error(`Failed to save muted word`, {message: e.message}) 66 78 setError(e.message) 67 79 } 68 - }, [field, options, addMutedWord, setField]) 80 + }, [_, field, options, addMutedWord, setField]) 69 81 70 82 return ( 71 83 <Dialog.ScrollableInner label={_(msg`Manage your muted words and tags`)}> ··· 87 99 label={_(msg`Enter a word or tag`)} 88 100 placeholder={_(msg`Enter a word or tag`)} 89 101 value={field} 90 - onChangeText={setField} 102 + onChangeText={value => { 103 + if (error) { 104 + setError('') 105 + } 106 + setField(value) 107 + }} 91 108 onSubmitEditing={submit} 92 109 /> 93 110 ··· 99 116 <View 100 117 style={[ 101 118 a.pt_sm, 102 - a.pb_md, 119 + a.py_sm, 103 120 a.flex_row, 104 121 a.align_center, 105 122 a.gap_sm, ··· 151 168 </View> 152 169 </Toggle.Group> 153 170 171 + {error && ( 172 + <View 173 + style={[ 174 + a.mb_lg, 175 + a.flex_row, 176 + a.rounded_sm, 177 + a.p_md, 178 + a.mb_xs, 179 + t.atoms.bg_contrast_25, 180 + { 181 + backgroundColor: t.palette.negative_400, 182 + }, 183 + ]}> 184 + <Text 185 + style={[ 186 + a.italic, 187 + {color: t.palette.white}, 188 + native({marginTop: 2}), 189 + ]}> 190 + {error} 191 + </Text> 192 + </View> 193 + )} 194 + 154 195 <Text 155 196 style={[ 197 + a.pt_xs, 156 198 a.text_sm, 157 199 a.italic, 158 200 a.leading_snug,
+33 -7
yarn.lock
··· 34 34 jsonpointer "^5.0.0" 35 35 leven "^3.1.0" 36 36 37 - "@atproto/api@^0.10.0": 38 - version "0.10.0" 39 - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.10.0.tgz#ca34dfa8f9b1e6ba021094c40cb0ff3c4c254044" 40 - integrity sha512-TSVCHh3UUZLtNzh141JwLicfYTc7TvVFvQJSWeOZLHr3Sk+9hqEY+9Itaqp1DAW92r4i25ChaMc/50sg4etAWQ== 37 + "@atproto/api@^0.10.3": 38 + version "0.10.3" 39 + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.10.3.tgz#cdef37a23b53e2e84840e527992482b0a0ab9d47" 40 + integrity sha512-eNP/6YLor48SUD38Jn5C7xocQL9XzW+BbYat2whWerKsFMn6Kfkk5O3fW1pvcc6NKtKVTo7/4ixMAS+dG2o/Yg== 41 41 dependencies: 42 42 "@atproto/common-web" "^0.2.3" 43 - "@atproto/lexicon" "^0.3.1" 44 - "@atproto/syntax" "^0.1.5" 45 - "@atproto/xrpc" "^0.4.1" 43 + "@atproto/lexicon" "^0.3.2" 44 + "@atproto/syntax" "^0.2.0" 45 + "@atproto/xrpc" "^0.4.2" 46 46 multiformats "^9.9.0" 47 47 tlds "^1.234.0" 48 48 typed-emitter "^2.1.0" ··· 245 245 multiformats "^9.9.0" 246 246 zod "^3.21.4" 247 247 248 + "@atproto/lexicon@^0.3.2": 249 + version "0.3.2" 250 + resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.3.2.tgz#0085a3acd3a77867b8efe188297a1bbacc55ce5c" 251 + integrity sha512-kmGCkrRwpWIqmn/KO4BZwUf8Nmfndk3XvFC06V0ygCWc42g6+t4QP/6ywNW4PgqfZY0Q5aW4EuDfD7KjAFkFtQ== 252 + dependencies: 253 + "@atproto/common-web" "^0.2.3" 254 + "@atproto/syntax" "^0.2.0" 255 + iso-datestring-validator "^2.2.2" 256 + multiformats "^9.9.0" 257 + zod "^3.21.4" 258 + 248 259 "@atproto/ozone@^0.0.7": 249 260 version "0.0.7" 250 261 resolved "https://registry.yarnpkg.com/@atproto/ozone/-/ozone-0.0.7.tgz#bfad82bc1d0900e79401a82f13581f707415505a" ··· 340 351 dependencies: 341 352 "@atproto/common-web" "^0.2.3" 342 353 354 + "@atproto/syntax@^0.2.0": 355 + version "0.2.0" 356 + resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.2.0.tgz#4bab724c02e11f8943b8ec101251082cf55067e9" 357 + integrity sha512-K+9jl6mtxC9ytlR7msSiP9jVNqtdxEBSt0kOfsC924lqGwuD8nlUAMi1GSMgAZJGg/Rd+0MKXh789heTdeL3HQ== 358 + dependencies: 359 + "@atproto/common-web" "^0.2.3" 360 + 343 361 "@atproto/xrpc-server@^0.4.2": 344 362 version "0.4.2" 345 363 resolved "https://registry.yarnpkg.com/@atproto/xrpc-server/-/xrpc-server-0.4.2.tgz#23efd89086b85933f1b0cc00c86e895adcaac315" ··· 363 381 integrity sha512-EMRGiu6oDvFL03Hk2rG/WCL3QK0GjZs9psH80JVf8z2nfdsGON6yn0hw3jvRB26CBXqi58U8Uicyq8Ej5pVTAA== 364 382 dependencies: 365 383 "@atproto/lexicon" "^0.3.1" 384 + zod "^3.21.4" 385 + 386 + "@atproto/xrpc@^0.4.2": 387 + version "0.4.2" 388 + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.4.2.tgz#57812e0624be597b85f21471acf336513f35ccda" 389 + integrity sha512-x4x2QB4nWmLjIpz2Ue9n/QVbVyJkk6tQMhvmDQaVFF89E3FcVI4rxF4uhzSxaLpbNtyVQBNEEmNHOr5EJLeHVA== 390 + dependencies: 391 + "@atproto/lexicon" "^0.3.2" 366 392 zod "^3.21.4" 367 393 368 394 "@aws-crypto/crc32@3.0.0":