From 329ca138ed383f45e6e87433c72ce5880b23cede Mon Sep 17 00:00:00 2001 From: Violet Caulfield <42452695+anultravioletaurora@users.noreply.github.com> Date: Mon, 8 Sep 2025 23:21:34 -0500 Subject: [PATCH] Player Render Optimizations, Better DeviceProfile Handling (#520) removes hooks from player provider in lieu of nonreactive functions and data fetching. In testing this fixed the issue where the player provider was rerendering when the queue or the currently active track changed Use a UUID to distinguish between DeviceProfiles, not the name. This means that media info from Jellyfin will be properly refetched if the user selects a different audio quality mini player rendering optimization fixes, since we don't need that rerendering 4 times a second when updates are only distinguishable every whole second. Also brings some style fixes that reduces vertical height usage update sentry sdk while we're in there doing debugging --- ios/Podfile.lock | 14 +- maestro/tests/6-settings.yaml | 2 - package.json | 4 +- patches/@sentry+react-native+6.17.0.patch | 26 -- .../mutations/download/offlineModeUtils.ts | 5 +- src/api/mutations/download/utils/index.ts | 24 ++ src/api/queries/download/constants/index.ts | 8 + src/api/queries/download/index.ts | 8 +- src/api/queries/media/keys.ts | 2 +- src/components/Global/helpers/slider.tsx | 2 +- src/components/Player/components/scrubber.tsx | 6 +- src/components/Player/mini-player.tsx | 148 ++++++------ src/player/config.ts | 10 + src/providers/Player/functions/index.ts | 5 +- .../Player/functions/initialization.ts | 22 ++ src/providers/Player/hooks/mutations.ts | 27 --- src/providers/Player/index.tsx | 145 ++++++------ src/utils/device-profiles.ts | 3 +- yarn.lock | 224 +++++++++--------- 19 files changed, 335 insertions(+), 350 deletions(-) delete mode 100644 patches/@sentry+react-native+6.17.0.patch create mode 100644 src/api/mutations/download/utils/index.ts create mode 100644 src/api/queries/download/constants/index.ts create mode 100644 src/providers/Player/functions/initialization.ts diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 8783cf05..24168f9a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1893,7 +1893,7 @@ PODS: - SocketRocket - SSZipArchive (~> 2.4.3) - Yoga - - react-native-pager-view (7.0.0): + - react-native-pager-view (6.9.1): - boost - DoubleConversion - fast_float @@ -2816,7 +2816,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - RNSentry (6.17.0): + - RNSentry (7.0.1): - boost - DoubleConversion - fast_float @@ -2843,7 +2843,7 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Sentry/HybridSDK (= 8.53.1) + - Sentry/HybridSDK (= 8.53.2) - SocketRocket - Yoga - RNWorklets (0.4.1): @@ -2938,7 +2938,7 @@ PODS: - SDWebImageWebPCoder (0.8.5): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.10) - - Sentry/HybridSDK (8.53.1) + - Sentry/HybridSDK (8.53.2) - SocketRocket (0.7.1) - SSZipArchive (2.4.3) - SwiftAudioEx (1.1.0) @@ -3311,7 +3311,7 @@ SPEC CHECKSUMS: react-native-mmkv: 560d39188cf4d817fb34b0df79426a298934ee7d react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 react-native-ota-hot-update: 5c8fe703c7a789f6de651030e4740923c77fc610 - react-native-pager-view: 0b0b445d3cb9f8e9972842edf6ddf892b46bdc55 + react-native-pager-view: a0516effb17ca5120ac2113bfd21b91130ad5748 react-native-safe-area-context: c6e2edd1c1da07bdce287fa9d9e60c5f7b514616 react-native-track-player: 89d8e641c83a89bea5dee43c381be743282553e9 react-native-vector-icons-material-design-icons: c502df5b988ce85d6c7d2b7ee909818315760b82 @@ -3355,11 +3355,11 @@ SPEC CHECKSUMS: RNReactNativeHapticFeedback: be4f1b4bf0398c30b59b76ed92ecb0a2ff3a69c6 RNReanimated: ee96d03fe3713993a30cc205522792b4cb08e4f9 RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c - RNSentry: 95e1ed0ede28a4af58aaafedeac9fcfaba0e89ce + RNSentry: 6c63debc7b22a00cbf7d1c9ed8de43e336216545 RNWorklets: e8335dff9d27004709f58316985769040cd1e8f2 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d - Sentry: 1e4e974d45f09d153af4b30b42acfb1c79e957d3 + Sentry: 59993bffde4a1ac297ba6d268dc4bbce068d7c1b SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef SwiftAudioEx: f6aa653770f3a0d3851edaf8d834a30aee4a7646 diff --git a/maestro/tests/6-settings.yaml b/maestro/tests/6-settings.yaml index 77f62564..f96561db 100644 --- a/maestro/tests/6-settings.yaml +++ b/maestro/tests/6-settings.yaml @@ -65,8 +65,6 @@ appId: com.jellify # Test About (Info) Tab - tapOn: text: "About" -- assertVisible: - text: "Made with love" - assertVisible: text: "View Source" - assertVisible: diff --git a/package.json b/package.json index 363243df..92550556 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@react-navigation/material-top-tabs": "^7.3.7", "@react-navigation/native": "^7.1.17", "@react-navigation/native-stack": "^7.3.26", - "@sentry/react-native": "6.17.0", + "@sentry/react-native": "7.0.1", "@shopify/flash-list": "^2.0.3", "@tamagui/config": "^1.132.23", "@tanstack/query-async-storage-persister": "^5.87.1", @@ -79,7 +79,7 @@ "react-native-linear-gradient": "^2.8.3", "react-native-mmkv": "3.3.0", "react-native-ota-hot-update": "2.3.1", - "react-native-pager-view": "^7.0.0", + "react-native-pager-view": "^6.9.1", "react-native-reanimated": "4.0.2", "react-native-safe-area-context": "^5.6.1", "react-native-screens": "4.16.0", diff --git a/patches/@sentry+react-native+6.17.0.patch b/patches/@sentry+react-native+6.17.0.patch deleted file mode 100644 index 3048e209..00000000 --- a/patches/@sentry+react-native+6.17.0.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/node_modules/@sentry/react-native/ios/RNSentry.mm b/node_modules/@sentry/react-native/ios/RNSentry.mm -index 267c41c..b731bad 100644 ---- a/node_modules/@sentry/react-native/ios/RNSentry.mm -+++ b/node_modules/@sentry/react-native/ios/RNSentry.mm -@@ -819,7 +819,7 @@ + (SentryUser *_Nullable)userFrom:(NSDictionary *)userKeys - { - #if SENTRY_PROFILING_ENABLED - try { -- facebook::hermes::HermesRuntime::enableSamplingProfiler(); -+// facebook::hermes::HermesRuntime::enableSamplingProfiler(); - if (nativeProfileTraceId == nil && nativeProfileStartTime == 0 && platformProfilers) { - # if SENTRY_TARGET_PROFILING_SUPPORTED - nativeProfileTraceId = [RNSentryId newId]; -@@ -879,10 +879,10 @@ + (SentryUser *_Nullable)userFrom:(NSDictionary *)userKeys - nativeProfileTraceId = nil; - nativeProfileStartTime = 0; - -- facebook::hermes::HermesRuntime::disableSamplingProfiler(); -+// facebook::hermes::HermesRuntime::; - std::stringstream ss; - // Before RN 0.69 Hermes used llvh::raw_ostream (profiling is supported for 0.69 and newer) -- facebook::hermes::HermesRuntime::dumpSampledTraceToStream(ss); -+// facebook::hermes::HermesRuntime::dumpSampledTraceToStream(ss); - - std::string s = ss.str(); - NSString *data = [NSString stringWithCString:s.c_str() diff --git a/src/api/mutations/download/offlineModeUtils.ts b/src/api/mutations/download/offlineModeUtils.ts index ba7bfa0b..d47d09af 100644 --- a/src/api/mutations/download/offlineModeUtils.ts +++ b/src/api/mutations/download/offlineModeUtils.ts @@ -8,9 +8,8 @@ import { JellifyDownloadProgress, JellifyDownloadProgressState, } from '../../../types/JellifyDownload' -import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models' import { queryClient } from '../../../constants/query-client' -import { QueryKeys } from '../../../enums/query-keys' +import { AUDIO_CACHE_QUERY } from '../../queries/download/constants' export async function downloadJellyfinFile( url: string, @@ -158,7 +157,7 @@ export const saveAudio = async ( return false } mmkv.set(MMKV_OFFLINE_MODE_KEYS.AUDIO_CACHE, JSON.stringify(existingArray)) - queryClient.invalidateQueries({ queryKey: [QueryKeys.AudioCache] }) + queryClient.invalidateQueries(AUDIO_CACHE_QUERY) return true } diff --git a/src/api/mutations/download/utils/index.ts b/src/api/mutations/download/utils/index.ts new file mode 100644 index 00000000..e1872f5f --- /dev/null +++ b/src/api/mutations/download/utils/index.ts @@ -0,0 +1,24 @@ +import { Api } from '@jellyfin/sdk/lib/api' +import { BaseItemDto, DeviceProfile } from '@jellyfin/sdk/lib/generated-client' +import { getAudioCache, saveAudio } from '../offlineModeUtils' +import { mapDtoToTrack } from '../../../../utils/mappings' + +export default async function saveAudioItem( + api: Api | undefined, + item: BaseItemDto, + deviceProfile: DeviceProfile, + autoCached: boolean = false, +) { + if (!api) return Promise.reject('API Instance not set') + + const downloadedTracks = getAudioCache() + + // If we already have this track downloaded, resolve the promise + if (downloadedTracks?.filter((download) => download.item.Id === item.Id).length ?? 0 > 0) + return Promise.resolve(false) + + const track = mapDtoToTrack(api, item, downloadedTracks ?? [], deviceProfile) + + // TODO: fix download progresses + return saveAudio(track, () => {}, autoCached) +} diff --git a/src/api/queries/download/constants/index.ts b/src/api/queries/download/constants/index.ts new file mode 100644 index 00000000..cc262071 --- /dev/null +++ b/src/api/queries/download/constants/index.ts @@ -0,0 +1,8 @@ +import { getAudioCache } from '../../../mutations/download/offlineModeUtils' +import DownloadQueryKeys from '../keys' + +export const AUDIO_CACHE_QUERY = { + queryKey: [DownloadQueryKeys.DownloadedTracks], + queryFn: getAudioCache, + staleTime: Infinity, // Never stale, we will manually refetch when downloads are completed +} diff --git a/src/api/queries/download/index.ts b/src/api/queries/download/index.ts index be825bb6..638b3c1d 100644 --- a/src/api/queries/download/index.ts +++ b/src/api/queries/download/index.ts @@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query' import fetchStorageInUse from './utils/storage-in-use' import { getAudioCache } from '../../mutations/download/offlineModeUtils' import DownloadQueryKeys from './keys' +import { AUDIO_CACHE_QUERY } from './constants' export const useStorageInUse = () => useQuery({ @@ -10,12 +11,7 @@ export const useStorageInUse = () => queryFn: fetchStorageInUse, }) -export const useAllDownloadedTracks = () => - useQuery({ - queryKey: [DownloadQueryKeys.DownloadedTracks], - queryFn: getAudioCache, - staleTime: Infinity, // Never stale, we will manually refetch when downloads are completed - }) +export const useAllDownloadedTracks = () => useQuery(AUDIO_CACHE_QUERY) export const useDownloadedTracks = (itemIds: (string | null | undefined)[]) => useAllDownloadedTracks().data?.filter((download) => itemIds.includes(download.item.Id)) diff --git a/src/api/queries/media/keys.ts b/src/api/queries/media/keys.ts index ef842ac5..cbd10913 100644 --- a/src/api/queries/media/keys.ts +++ b/src/api/queries/media/keys.ts @@ -9,7 +9,7 @@ interface MediaInfoQueryProps { const MediaInfoQueryKey = ({ api, deviceProfile, itemId }: MediaInfoQueryProps) => [ 'MEDIA_INFO', api, - deviceProfile?.Name, + deviceProfile?.Id, itemId, ] diff --git a/src/components/Global/helpers/slider.tsx b/src/components/Global/helpers/slider.tsx index 2b43b9d4..d55a6d06 100644 --- a/src/components/Global/helpers/slider.tsx +++ b/src/components/Global/helpers/slider.tsx @@ -51,7 +51,7 @@ export function HorizontalSlider({ value, max, width, props }: SliderProps): Rea {...props} > - + + {nowPlaying && ( - <> - - - - - - navigation.navigate('PlayerRoot', { screen: 'PlayerScreen' }) - } - > - - {api && ( - - - - )} - - - - - + + + + navigation.navigate('PlayerRoot', { screen: 'PlayerScreen' }) + } + > + + {api && ( - - - - {nowPlaying?.title ?? 'Nothing Playing'} - - - - - - {nowPlaying?.artist ?? ''} - - - + - + )} + - + + + - - + + + + {nowPlaying?.title ?? 'Nothing Playing'} + + + + + + {nowPlaying?.artist ?? ''} + + + + + + + + - - - + + + + + )} - + ) }) function MiniPlayerRuntime(): React.JSX.Element { - const { position } = useProgress(UPDATE_INTERVAL) + const { position } = useProgress(MINIPLAYER_UPDATE_INTERVAL) const { data: nowPlaying } = useNowPlaying() const { duration } = nowPlaying! @@ -198,11 +187,11 @@ function MiniPlayerRuntime(): React.JSX.Element { } function MiniPlayerProgress(): React.JSX.Element { - const progress = useProgress(UPDATE_INTERVAL) + const progress = useProgress(MINIPLAYER_UPDATE_INTERVAL) return ( index)}`, + ) + + if (!isUndefined(storedPlayQueue) && !isUndefined(storedIndex)) { + console.debug('Initializing play queue from storage') + + await TrackPlayer.reset() + await TrackPlayer.add(storedPlayQueue) + await TrackPlayer.skip(storedIndex) + + console.debug('Initialized play queue from storage') + } +} diff --git a/src/providers/Player/hooks/mutations.ts b/src/providers/Player/hooks/mutations.ts index 905663d6..b63d91ea 100644 --- a/src/providers/Player/hooks/mutations.ts +++ b/src/providers/Player/hooks/mutations.ts @@ -30,33 +30,6 @@ const PLAYER_MUTATION_OPTIONS = { retry: false, } -/** - * - * @returns a mutation hook - */ -export const useInitialization = () => - useMutation({ - mutationFn: async () => { - const storedPlayQueue = getPlayQueue() - const storedIndex = getActiveIndex() - - console.debug( - `StoredIndex: ${storedIndex}, storedPlayQueue: ${storedPlayQueue?.map((track, index) => index)}`, - ) - - if (!isUndefined(storedPlayQueue) && !isUndefined(storedIndex)) { - console.debug('Initializing play queue from storage') - - await TrackPlayer.reset() - await TrackPlayer.add(storedPlayQueue) - await TrackPlayer.skip(storedIndex) - - console.debug('Initialized play queue from storage') - } - }, - onSuccess: async () => console.debug('Play Queue initialized from queryables'), - }) - /** * A mutation to handle starting playback */ diff --git a/src/providers/Player/index.tsx b/src/providers/Player/index.tsx index f3838e0d..e28871ca 100644 --- a/src/providers/Player/index.tsx +++ b/src/providers/Player/index.tsx @@ -1,19 +1,23 @@ import { usePerformanceMonitor } from '../../hooks/use-performance-monitor' -import { Event, State, useTrackPlayerEvents } from 'react-native-track-player' -import { refetchNowPlaying } from './functions/queries' -import { createContext, useEffect } from 'react' -import { useAudioNormalization, useInitialization } from './hooks/mutations' -import { useCurrentIndex, useNowPlaying, useQueue } from './hooks/queries' +import TrackPlayer, { Event, State, useTrackPlayerEvents } from 'react-native-track-player' +import { createContext, useCallback, useEffect } from 'react' import { handleActiveTrackChanged } from './functions' import JellifyTrack from '../../types/JellifyTrack' import { useIsRestoring } from '@tanstack/react-query' -import { - useReportPlaybackProgress, - useReportPlaybackStarted, - useReportPlaybackStopped, -} from '../../api/mutations/playback' -import { useDownloadAudioItem } from '../../api/mutations/download' import { useAutoDownload } from '../../stores/settings/usage' +import { queryClient } from '../../constants/query-client' +import { NOW_PLAYING_QUERY_KEY } from './constants/query-keys' +import reportPlaybackStopped from '../../api/mutations/playback/functions/playback-stopped' +import reportPlaybackCompleted from '../../api/mutations/playback/functions/playback-completed' +import isPlaybackFinished from '../../api/mutations/playback/utils' +import { useJellifyContext } from '..' +import reportPlaybackProgress from '../../api/mutations/playback/functions/playback-progress' +import reportPlaybackStarted from '../../api/mutations/playback/functions/playback-started' +import calculateTrackVolume from './utils/normalization' +import saveAudioItem from '../../api/mutations/download/utils' +import { useDownloadingDeviceProfile } from '../../stores/device-profile' +import { NOW_PLAYING_QUERY } from './constants/queries' +import Initialize from './functions/initialization' const PLAYER_EVENTS: Event[] = [ Event.PlaybackActiveTrackChanged, @@ -26,78 +30,75 @@ interface PlayerContext {} export const PlayerContext = createContext({}) export const PlayerProvider: () => React.JSX.Element = () => { + const { api } = useJellifyContext() + const [autoDownload] = useAutoDownload() + const downloadingDeviceProfile = useDownloadingDeviceProfile() + usePerformanceMonitor('PlayerProvider', 3) - const { mutate: initializePlayQueue } = useInitialization() - - const { data: currentIndex } = useCurrentIndex() - - const { data: playQueue } = useQueue() - - const { data: nowPlaying } = useNowPlaying() - - const { mutate: normalizeAudioVolume } = useAudioNormalization() - - const { mutate: reportPlaybackStarted } = useReportPlaybackStarted() - const { mutate: reportPlaybackProgress } = useReportPlaybackProgress() - const { mutate: reportPlaybackStopped } = useReportPlaybackStopped() - - const [downloadProgress, downloadAudioItem] = useDownloadAudioItem() - const isRestoring = useIsRestoring() - useTrackPlayerEvents(PLAYER_EVENTS, (event) => { - switch (event.type) { - case Event.PlaybackActiveTrackChanged: - if (event.track) normalizeAudioVolume(event.track as JellifyTrack) + const eventHandler = useCallback( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async (event: any) => { + let nowPlaying: JellifyTrack | undefined - handleActiveTrackChanged() - refetchNowPlaying() + switch (event.type) { + case Event.PlaybackActiveTrackChanged: + await handleActiveTrackChanged() - if (event.lastTrack) - reportPlaybackStopped({ - track: event.lastTrack as JellifyTrack, - lastPosition: event.lastPosition, - duration: (event.lastTrack as JellifyTrack).duration, - }) - break - case Event.PlaybackProgressUpdated: - console.debug(`Completion percentage: ${event.position / event.duration}`) - if (nowPlaying) - reportPlaybackProgress({ - track: nowPlaying, - position: event.position, - }) + if (event.track) { + nowPlaying = event.track as JellifyTrack - if (event.position / event.duration > 0.3 && autoDownload && nowPlaying) - downloadAudioItem({ item: nowPlaying.item, autoCached: true }) - break - case Event.PlaybackState: - switch (event.state) { - case State.Playing: - if (nowPlaying) - reportPlaybackStarted({ - track: nowPlaying, - }) - break - case State.Paused: - case State.Stopped: - case State.Ended: - if (nowPlaying) - reportPlaybackStopped({ - track: nowPlaying, - lastPosition: 0, - duration: nowPlaying.duration, - }) - } - break - } - }) + const volume = calculateTrackVolume(nowPlaying) + await TrackPlayer.setVolume(volume) + } + + if (event.lastTrack) + if (isPlaybackFinished(event.lastPosition, event.lastTrack.duration ?? 1)) + await reportPlaybackCompleted(api, event.lastTrack as JellifyTrack) + else await reportPlaybackStopped(api, event.lastTrack as JellifyTrack) + + break + + case Event.PlaybackProgressUpdated: + console.debug(`Completion percentage: ${event.position / event.duration}`) + + nowPlaying = queryClient.getQueryData(NOW_PLAYING_QUERY_KEY) + + if (nowPlaying) { + reportPlaybackProgress(api, nowPlaying, event.position) + } + + if (event.position / event.duration > 0.3 && autoDownload && nowPlaying) + saveAudioItem(api, nowPlaying.item, downloadingDeviceProfile, true) + break + + case Event.PlaybackState: + nowPlaying = queryClient.getQueryData(NOW_PLAYING_QUERY_KEY) + + switch (event.state) { + case State.Playing: + if (nowPlaying) reportPlaybackStarted(api, nowPlaying) + queryClient.ensureQueryData(NOW_PLAYING_QUERY) + break + case State.Paused: + case State.Stopped: + case State.Ended: + if (nowPlaying) reportPlaybackStopped(api, nowPlaying) + } + break + } + }, + [api, autoDownload], + ) + + useTrackPlayerEvents(PLAYER_EVENTS, eventHandler) useEffect(() => { - if (!isRestoring) initializePlayQueue() + if (!isRestoring) Initialize() }, [isRestoring]) return ( diff --git a/src/utils/device-profiles.ts b/src/utils/device-profiles.ts index 24fb65a8..ba85d429 100644 --- a/src/utils/device-profiles.ts +++ b/src/utils/device-profiles.ts @@ -19,11 +19,11 @@ import { EncodingContext, MediaStreamProtocol, } from '@jellyfin/sdk/lib/generated-client' -import { Platform } from 'react-native' import { getQualityParams } from './mappings' import { capitalize } from 'lodash' import { SourceType } from '../types/JellifyTrack' import StreamingQuality from '../enums/audio-quality' +import uuid from 'react-native-uuid' /** * A constant that defines the options for the {@link useDeviceProfile} hook - building the @@ -39,6 +39,7 @@ export function getDeviceProfile( type: SourceType, ): DeviceProfile { return { + Id: uuid.v4(), Name: `${capitalize(streamingQuality)} Quality Audio ${capitalize(type)}`, MaxStaticBitrate: streamingQuality === 'original' diff --git a/yarn.lock b/yarn.lock index 30049cf1..43b3044f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2203,96 +2203,96 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@sentry-internal/browser-utils@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.54.0.tgz#2d68c7fa843db867ed98059faf1a750be3eca95a" - integrity sha512-DKWCqb4YQosKn6aD45fhKyzhkdG7N6goGFDeyTaJFREJDFVDXiNDsYZu30nJ6BxMM7uQIaARhPAC5BXfoED3pQ== +"@sentry-internal/browser-utils@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-10.8.0.tgz#a028e8067566cb80026c112cd62b5c119415e337" + integrity sha512-FaQX9eefc8sh3h3ZQy16U73KiH0xgDldXnrFiWK6OeWg8X4bJpnYbLqEi96LgHiQhjnnz+UQP1GDzH5oFuu5fA== dependencies: - "@sentry/core" "8.54.0" + "@sentry/core" "10.8.0" -"@sentry-internal/feedback@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.54.0.tgz#52c3a63aa5b520eca7acfa1376621e8441984126" - integrity sha512-nQqRacOXoElpE0L0ADxUUII0I3A94niqG9Z4Fmsw6057QvyrV/LvTiMQBop6r5qLjwMqK+T33iR4/NQI5RhsXQ== +"@sentry-internal/feedback@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-10.8.0.tgz#fa562fe64c806d429f4c33acd8e7ca0f929053f3" + integrity sha512-n7SqgFQItq4QSPG7bCjcZcIwK6AatKnnmSDJ/i6e8jXNIyLwkEuY2NyvTXACxVdO/kafGD5VmrwnTo3Ekc1AMg== dependencies: - "@sentry/core" "8.54.0" + "@sentry/core" "10.8.0" -"@sentry-internal/replay-canvas@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.54.0.tgz#e57a3893db2bb0ea7ad9dc2a804bb035142fe3ba" - integrity sha512-K/On3OAUBeq/TV2n+1EvObKC+WMV9npVXpVyJqCCyn8HYMm8FUGzuxeajzm0mlW4wDTPCQor6mK9/IgOquUzCw== +"@sentry-internal/replay-canvas@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-10.8.0.tgz#5adc2f3aa7036fed46415fcb6eabd4d8a6d335e3" + integrity sha512-jC4OOwiNgrlIPeXIPMLkaW53BSS1do+toYHoWzzO5AXGpN6jRhanoSj36FpVuH2N3kFnxKVfVxrwh8L+/3vFWg== dependencies: - "@sentry-internal/replay" "8.54.0" - "@sentry/core" "8.54.0" + "@sentry-internal/replay" "10.8.0" + "@sentry/core" "10.8.0" -"@sentry-internal/replay@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.54.0.tgz#b92990a51ffbe8d92998ff8188db9e3a6f9d1e18" - integrity sha512-8xuBe06IaYIGJec53wUC12tY2q4z2Z0RPS2s1sLtbA00EvK1YDGuXp96IDD+HB9mnDMrQ/jW5f97g9TvPsPQUg== +"@sentry-internal/replay@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-10.8.0.tgz#3f14329924ff744611296ce4e9588530e5f168e4" + integrity sha512-9+qDEoEjv4VopLuOzK1zM4LcvcUsvB5N0iJ+FRCM3XzzOCbebJOniXTQbt5HflJc3XLnQNKFdKfTfgj8M/0RKQ== dependencies: - "@sentry-internal/browser-utils" "8.54.0" - "@sentry/core" "8.54.0" + "@sentry-internal/browser-utils" "10.8.0" + "@sentry/core" "10.8.0" -"@sentry/babel-plugin-component-annotate@3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.5.0.tgz#1b0d01f903b725da876117d551610085c3dd21c7" - integrity sha512-s2go8w03CDHbF9luFGtBHKJp4cSpsQzNVqgIa9Pfa4wnjipvrK6CxVT4icpLA3YO6kg5u622Yoa5GF3cJdippw== +"@sentry/babel-plugin-component-annotate@4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-4.3.0.tgz#c5b6cbb986952596d3ad233540a90a1fd18bad80" + integrity sha512-OuxqBprXRyhe8Pkfyz/4yHQJc5c3lm+TmYWSSx8u48g5yKewSQDOxkiLU5pAk3WnbLPy8XwU/PN+2BG0YFU9Nw== -"@sentry/browser@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.54.0.tgz#5487075908aac564892e689e1b6d233fdb314f5b" - integrity sha512-BgUtvxFHin0fS0CmJVKTLXXZcke0Av729IVfi+2fJ4COX8HO7/HAP02RKaSQGmL2HmvWYTfNZ7529AnUtrM4Rg== +"@sentry/browser@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-10.8.0.tgz#f33b95f48e3967db661db1666ad3e1dc0a6922fb" + integrity sha512-2J7HST8/ixCaboq17yFn/j/OEokXSXoCBMXRrFx4FKJggKWZ90e2Iau5mP/IPPhrW+W9zCptCgNMY0167wS4qA== dependencies: - "@sentry-internal/browser-utils" "8.54.0" - "@sentry-internal/feedback" "8.54.0" - "@sentry-internal/replay" "8.54.0" - "@sentry-internal/replay-canvas" "8.54.0" - "@sentry/core" "8.54.0" + "@sentry-internal/browser-utils" "10.8.0" + "@sentry-internal/feedback" "10.8.0" + "@sentry-internal/replay" "10.8.0" + "@sentry-internal/replay-canvas" "10.8.0" + "@sentry/core" "10.8.0" -"@sentry/cli-darwin@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.47.0.tgz#171d4ed94a035b35e7cba21e133351fa1d8a5664" - integrity sha512-xEFppdMQogV1A85A/s+Al1VH0NHXk7syy+5BL/jYd168FPeVB3iERP0AwP4h9UhR3/wTe1lTb+tfOKpXrECLCw== +"@sentry/cli-darwin@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.53.0.tgz#0584f5a4a376c9373f91ad5e1d9194278be2aed6" + integrity sha512-NNPfpILMwKgpHiyJubHHuauMKltkrgLQ5tvMdxNpxY60jBNdo5VJtpESp4XmXlnidzV4j1z61V4ozU6ttDgt5Q== -"@sentry/cli-linux-arm64@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.47.0.tgz#9802fe08164217483926ce8a1becf45f740fea20" - integrity sha512-qjF87W0Vo5vITbm4GXjtX8uQCDRg2gVT0yP1Uz12IuBri80iJj66IANX1wbae2mG2Io1Ibc4AKN5FWd2HpPiKw== +"@sentry/cli-linux-arm64@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.53.0.tgz#04a73b2592edf10d6e06957905becc98692605b1" + integrity sha512-xY/CZ1dVazsSCvTXzKpAgXaRqfljVfdrFaYZRUaRPf1ZJRGa3dcrivoOhSIeG/p5NdYtMvslMPY9Gm2MT0M83A== -"@sentry/cli-linux-arm@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.47.0.tgz#32221dcfe46024babf43d846a1e2d05a57b153a8" - integrity sha512-tE8gDcp2qFCTtndz1ViLAo+JNQEEjniBFJAWIFh1utJKwBxBStB0JDporOZHvWUcnSCP5F+W59iuir2YAAQh/w== +"@sentry/cli-linux-arm@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.53.0.tgz#caa1dceb23ee40e9d0c82a7c6156c3f010eebc0e" + integrity sha512-NdRzQ15Ht83qG0/Lyu11ciy/Hu/oXbbtJUgwzACc7bWvHQA8xEwTsehWexqn1529Kfc5EjuZ0Wmj3MHmp+jOWw== -"@sentry/cli-linux-i686@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.47.0.tgz#e551e813e8060de161d6058664e252c952f22291" - integrity sha512-5FYe1dth06xThbr41AOvX67oKZr4xqtDwHJvpFdyCdf+Yh5E5/rtPX35K1beMERgVyT+whRetrNBFAcHnp6LaA== +"@sentry/cli-linux-i686@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.53.0.tgz#989dc766b098e94c6751bad3efcd4ca0fe1a2565" + integrity sha512-0REmBibGAB4jtqt9S6JEsFF4QybzcXHPcHtJjgMi5T0ueh952uG9wLzjSxQErCsxTKF+fL8oG0Oz5yKBuCwCCQ== -"@sentry/cli-linux-x64@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.47.0.tgz#56c257e4df8466709fb80ec21e1b5350ee713464" - integrity sha512-wq67T2UpbTst//1lZGDTeFa7nKsnOpP8rS34TQ3GxsGU1LOjinl9zYl0mUPsoVXIHbWxTHlU6YDNf0q0eB7ddA== +"@sentry/cli-linux-x64@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.53.0.tgz#2a94361233ed24e4a32f08919011a591aea4cb6b" + integrity sha512-9UGJL+Vy5N/YL1EWPZ/dyXLkShlNaDNrzxx4G7mTS9ywjg+BIuemo6rnN7w43K1NOjObTVO6zY0FwumJ1pCyLg== -"@sentry/cli-win32-arm64@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.47.0.tgz#ce7914253f15160373e856e48738932f03adef41" - integrity sha512-a1sv44bMe35V9eW9Zk/kYymXswzJ/RHXNRjkFnW1m1iXx6NauQD3sjEgkryu3UmuvKO9g3pBkMMT1u6xB/08QA== +"@sentry/cli-win32-arm64@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.53.0.tgz#946609eabd318657521c4b3ef15a420cc00f1c60" + integrity sha512-G1kjOjrjMBY20rQcJV2GA8KQE74ufmROCDb2GXYRfjvb1fKAsm4Oh8N5+Tqi7xEHdjQoLPkE4CNW0aH68JSUDQ== -"@sentry/cli-win32-i686@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.47.0.tgz#c6414696b7031a590520b01e8a062e0fe71874be" - integrity sha512-QKLSCED00jNHC4cu9GutLWaFAy5vdVGDrIPvVdztSFLS2fRMhRSSPE8tJwlSYh2OfdHhUHQbMOo58cDVfEklBg== +"@sentry/cli-win32-i686@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.53.0.tgz#f51937d73cefad16b9d2e89acc4c9f178da36cc6" + integrity sha512-qbGTZUzesuUaPtY9rPXdNfwLqOZKXrJRC1zUFn52hdo6B+Dmv0m/AHwRVFHZP53Tg1NCa8bDei2K/uzRN0dUZw== -"@sentry/cli-win32-x64@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.47.0.tgz#96ceaf75a9ffb39fd255f11fa2b85f4e7e26b591" - integrity sha512-XcM+I7eWpSp8khy44djunVvQKSMsBP698j0swA41Pd1JL0mxLFV/4P9wfWZw1RRB8R71jks74kZvM45AAh2FZw== +"@sentry/cli-win32-x64@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.53.0.tgz#d89cde8354b4eb8e89f2c11dc6a6fb5e7392e2ae" + integrity sha512-1TXYxYHtwgUq5KAJt3erRzzUtPqg7BlH9T7MdSPHjJatkrr/kwZqnVe2H6Arr/5NH891vOlIeSPHBdgJUAD69g== -"@sentry/cli@2.47.0": - version "2.47.0" - resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.47.0.tgz#d9a3309d281d03e23651a68e81fbd04c60f52bfe" - integrity sha512-M1zAbc74rGqcWXPi4vowNY7plADjsvKVEZhyUcSq+K3JtZOQ1m1QJgSno31hLbK9V4sx4qyDesNEcBtUjof07w== +"@sentry/cli@2.53.0": + version "2.53.0" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.53.0.tgz#fd5b65b9f6f06f0ed16345acf3ecf0720bd7bcf8" + integrity sha512-n2ZNb+5Z6AZKQSI0SusQ7ZzFL637mfw3Xh4C3PEyVSn9LiF683fX0TTq8OeGmNZQS4maYfS95IFD+XpydU0dEA== dependencies: https-proxy-agent "^5.0.0" node-fetch "^2.6.7" @@ -2300,55 +2300,47 @@ proxy-from-env "^1.1.0" which "^2.0.2" optionalDependencies: - "@sentry/cli-darwin" "2.47.0" - "@sentry/cli-linux-arm" "2.47.0" - "@sentry/cli-linux-arm64" "2.47.0" - "@sentry/cli-linux-i686" "2.47.0" - "@sentry/cli-linux-x64" "2.47.0" - "@sentry/cli-win32-arm64" "2.47.0" - "@sentry/cli-win32-i686" "2.47.0" - "@sentry/cli-win32-x64" "2.47.0" + "@sentry/cli-darwin" "2.53.0" + "@sentry/cli-linux-arm" "2.53.0" + "@sentry/cli-linux-arm64" "2.53.0" + "@sentry/cli-linux-i686" "2.53.0" + "@sentry/cli-linux-x64" "2.53.0" + "@sentry/cli-win32-arm64" "2.53.0" + "@sentry/cli-win32-i686" "2.53.0" + "@sentry/cli-win32-x64" "2.53.0" -"@sentry/core@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.54.0.tgz#a2ebec965cadcb6de89e116689feeef79d5862a6" - integrity sha512-03bWf+D1j28unOocY/5FDB6bUHtYlm6m6ollVejhg45ZmK9iPjdtxNWbrLsjT1WRym0Tjzowu+A3p+eebYEv0Q== +"@sentry/core@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.8.0.tgz#71f71f8ecb5a06c41a426f5ccee2d9767b7d7cfd" + integrity sha512-scYzM/UOItu4PjEq6CpHLdArpXjIS0laHYxE4YjkIbYIH6VMcXGQbD/FSBClsnCr1wXRnlXfXBzj0hrQAFyw+Q== -"@sentry/react-native@6.17.0": - version "6.17.0" - resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-6.17.0.tgz#d897af3861251ced6ca0f60d015e1806b4ec575d" - integrity sha512-R8cQHE5wtespva5tYtBc620xI1+w5dI53fotdzX+ONxHs5G31Da9O1OwYLH9hh2WouIf4dDXfBSmnKoVXL79+Q== +"@sentry/react-native@7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-7.0.1.tgz#688a68bb1ec12a9e18577c72477593989ad1e6c0" + integrity sha512-xz8ON51qSDvcHVFkdLo0b7rlrQVXpRVXqzm7e1+nHEZ07TX0o+utxx04akxD1Z4hmGPTWPmsHeMlm7diV9NtTQ== dependencies: - "@sentry/babel-plugin-component-annotate" "3.5.0" - "@sentry/browser" "8.54.0" - "@sentry/cli" "2.47.0" - "@sentry/core" "8.54.0" - "@sentry/react" "8.54.0" - "@sentry/types" "8.54.0" - "@sentry/utils" "8.54.0" + "@sentry/babel-plugin-component-annotate" "4.3.0" + "@sentry/browser" "10.8.0" + "@sentry/cli" "2.53.0" + "@sentry/core" "10.8.0" + "@sentry/react" "10.8.0" + "@sentry/types" "10.8.0" -"@sentry/react@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.54.0.tgz#16cec103b5d5697bdfebacf6e2d35f19699b3ab3" - integrity sha512-42T/fp8snYN19Fy/2P0Mwotu4gcdy+1Lx+uYCNcYP1o7wNGigJ7qb27sW7W34GyCCHjoCCfQgeOqDQsyY8LC9w== +"@sentry/react@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-10.8.0.tgz#51020c04d9d6ce2a9edc3aa1bd961823f1a27561" + integrity sha512-w/dGLMCLJG2lp8gKVKX1jjeg2inXewKfPb73+PS1CDi9/ihvqZU2DAXxnaNsBA7YYtGwlWVJe1bLAqguwTEpqw== dependencies: - "@sentry/browser" "8.54.0" - "@sentry/core" "8.54.0" + "@sentry/browser" "10.8.0" + "@sentry/core" "10.8.0" hoist-non-react-statics "^3.3.2" -"@sentry/types@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.54.0.tgz#1d57bb094443081de4e0d8b638e6ebc40f5ddd36" - integrity sha512-wztdtr7dOXQKi0iRvKc8XJhJ7HaAfOv8lGu0yqFOFwBZucO/SHnu87GOPi8mvrTiy1bentQO5l+zXWAaMvG4uw== +"@sentry/types@10.8.0": + version "10.8.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-10.8.0.tgz#3c87e7d48bf2755841e75e078ff0fb17ff36a37f" + integrity sha512-xRe41/KvnNt4o6t5YeB+yBRTWvLUu6FJpft/VBOs4Bfh1/6rz+l78oxSCtpXo3MsfTd5185I0uuggAjEdD4Y6g== dependencies: - "@sentry/core" "8.54.0" - -"@sentry/utils@8.54.0": - version "8.54.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.54.0.tgz#5e28e03a249451b4a55200a0787f4e2c59bab2c5" - integrity sha512-JL8UDjrsKxKclTdLXfuHfE7B3KbrAPEYP7tMyN/xiO2vsF6D84fjwYyalO0ZMtuFZE6vpSze8ZOLEh6hLnPYsw== - dependencies: - "@sentry/core" "8.54.0" + "@sentry/core" "10.8.0" "@shopify/flash-list@^2.0.3": version "2.0.3" @@ -8554,10 +8546,10 @@ react-native-ota-hot-update@2.3.1: buffer "^6.0.3" isomorphic-git "1.27.3" -react-native-pager-view@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-7.0.0.tgz#09e72960776d2a95d7b0bc5c71aa2b808a7ca4a4" - integrity sha512-RgpGiTqE7UoSvCMG//AkiMrReF3NxtCfeCiRSvqxhYlTwHq3jMFWqAyZsyEepvCHYCYnMSmRGTMxv9koziat7g== +react-native-pager-view@^6.9.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.9.1.tgz#a9e6d9323935cc2ae1d46d7816b66f76dc3eff8e" + integrity sha512-uUT0MMMbNtoSbxe9pRvdJJKEi9snjuJ3fXlZhG8F2vVMOBJVt/AFtqMPUHu9yMflmqOr08PewKzj9EPl/Yj+Gw== react-native-reanimated@4.0.2: version "4.0.2"