From 0b0f68008a76003768de8b47062edf936e9eabe0 Mon Sep 17 00:00:00 2001 From: Debashish Patra Date: Tue, 31 Dec 2024 20:05:17 +0530 Subject: [PATCH] fix(v0.11.0): clear blocking bugs (#180) fix(mastodon): mentions tab fix: cannot click nav element to swipe pager chore: fix misskey mention list fix(notifications): misskey and mastodon fix(login): added saved client token expiry --- apps/mobile/app.config.ts | 1 + .../mobile/app/(tabs)/notifications/index.tsx | 32 ++- .../(tabs)/profile/onboard/signin-bsky.tsx | 2 +- .../profile/{ => settings}/accounts.tsx | 2 +- .../app/(tabs)/profile/settings/advanced.tsx | 38 +++ .../(tabs)/profile/settings/app-settings.tsx | 7 - .../app/(tabs)/profile/settings/general.tsx | 38 +++ .../(tabs)/profile/settings/goodie-hut.tsx | 38 +++ .../app/(tabs)/profile/settings/help.tsx | 115 -------- .../app/(tabs)/profile/settings/info.tsx | 45 --- .../app/(tabs)/profile/settings/support.tsx | 75 ----- .../app/(tabs)/profile/settings/wellbeing.tsx | 46 +++- .../common/media/NotificationMediaThumbs.tsx | 6 +- .../containers/SwipeableTabsContainer.tsx | 30 +- .../containers/UserGuideContainer.tsx | 9 +- .../AppBottomSheetSelectAccount.tsx | 2 +- .../components/error-screen/AppNoAccount.tsx | 2 +- apps/mobile/components/lib/AppPagerView.tsx | 7 +- .../components/screens/home/SocialHub.tsx | 2 +- .../landing/fragments/FlatListRenderer.tsx | 1 + .../landing/fragments/NotificationSender.tsx | 36 ++- .../fragments/NotificationSenderMini.tsx | 3 +- .../fragments/NotificationUpdateItem.tsx | 2 + .../segments/BoostNotificationFragment.tsx | 2 + .../FavouriteNotificationFragment.tsx | 8 +- .../segments/MentionNotificationFragment.tsx | 1 - .../notifications/landing/segments/_common.ts | 1 + .../notifications/landing/views/ChatView.tsx | 4 +- .../landing/views/MentionView.tsx | 17 +- .../landing/views/SocialView.tsx | 18 +- .../landing/views/UpdatesView.tsx | 8 +- .../landing/views/_container.tsx | 2 +- .../screens/profile/stack/AppSettingsPage.tsx | 128 +++++---- .../screens/profile/stack/SelectAccount.tsx | 80 ++++-- .../onboard/fragments/PleromaPasteToken.tsx | 2 +- .../stack/onboard/stacks/MastodonSignIn.tsx | 2 +- .../stack/onboard/stacks/MisskeySignIn.tsx | 2 +- .../screens/home/new-user/Introduction.tsx | 2 +- apps/mobile/hooks/api/useNotifications.ts | 258 ++++++++++++++++-- .../app/timelines/useAppTimelinePosts.tsx | 6 +- apps/mobile/package.json | 9 +- apps/mobile/services/activitypub.service.ts | 3 +- .../middlewares/notification.middleware.ts | 18 ++ apps/mobile/services/openai.service.ts | 47 ++-- apps/mobile/services/session/_shared.ts | 25 ++ .../services/session/app-session.service.ts | 13 +- apps/mobile/utils/route-list.ts | 8 +- .../_client/_router/routes/notifications.ts | 2 + .../adapters/_client/bluesky/notifications.ts | 4 + .../adapters/_client/default/notifications.ts | 9 +- .../_client/mastodon/notifications.ts | 26 +- .../adapters/_client/misskey/notifications.ts | 8 + .../adapters/_client/pleroma/notifications.ts | 4 + yarn.lock | 111 ++------ 54 files changed, 809 insertions(+), 558 deletions(-) rename apps/mobile/app/(tabs)/profile/{ => settings}/accounts.tsx (53%) create mode 100644 apps/mobile/app/(tabs)/profile/settings/advanced.tsx delete mode 100644 apps/mobile/app/(tabs)/profile/settings/app-settings.tsx create mode 100644 apps/mobile/app/(tabs)/profile/settings/general.tsx create mode 100644 apps/mobile/app/(tabs)/profile/settings/goodie-hut.tsx delete mode 100644 apps/mobile/app/(tabs)/profile/settings/help.tsx delete mode 100644 apps/mobile/app/(tabs)/profile/settings/info.tsx delete mode 100644 apps/mobile/app/(tabs)/profile/settings/support.tsx diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index eecab7e0..19a5c04e 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -43,6 +43,7 @@ const expo = ({ config }: ConfigContext): ExpoConfig => ({ }, newArchEnabled: true, plugins: [ + 'expo-sqlite', [ 'expo-build-properties', { diff --git a/apps/mobile/app/(tabs)/notifications/index.tsx b/apps/mobile/app/(tabs)/notifications/index.tsx index d7cd58dc..957cb537 100644 --- a/apps/mobile/app/(tabs)/notifications/index.tsx +++ b/apps/mobile/app/(tabs)/notifications/index.tsx @@ -3,7 +3,7 @@ import { useAppAcct, useAppTheme, } from '../../../hooks/utility/global-state-extractors'; -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import AppNoAccount from '../../../components/error-screen/AppNoAccount'; import { APP_LANDING_PAGE_TYPE } from '../../../components/shared/topnavbar/AppTabLandingNavbar'; import { View } from 'react-native'; @@ -11,8 +11,8 @@ import MentionView from '../../../components/screens/notifications/landing/views import ChatView from '../../../components/screens/notifications/landing/views/ChatView'; import SocialView from '../../../components/screens/notifications/landing/views/SocialView'; import UpdatesView from '../../../components/screens/notifications/landing/views/UpdatesView'; -import { AppPagerView } from '../../../components/lib/AppPagerView'; import { BottomNavBar } from '../../../components/shared/pager-view/BottomNavBar'; +import PagerView from 'react-native-pager-view'; const renderScene = (index: number) => { switch (index) { @@ -34,10 +34,17 @@ function Page() { const { acct } = useAppAcct(); const [Index, setIndex] = useState(0); - function onChipSelect(index: number) { + const ref = useRef(null); + const onChipSelect = (index: number) => { if (Index !== index) { - setIndex(index); + ref.current.setPage(index); } + }; + + function onPageScroll(e: any) { + const { offset, position } = e.nativeEvent; + const nextIdx = Math.round(position + offset); + setIndex(nextIdx); } useEffect(() => { @@ -74,11 +81,18 @@ function Page() { return ( - + + {Array.from({ length: tabLabels.length }).map((_, index) => ( + {renderScene(index)} + ))} + + ; diff --git a/apps/mobile/app/(tabs)/profile/settings/advanced.tsx b/apps/mobile/app/(tabs)/profile/settings/advanced.tsx new file mode 100644 index 00000000..6bd567cd --- /dev/null +++ b/apps/mobile/app/(tabs)/profile/settings/advanced.tsx @@ -0,0 +1,38 @@ +import { ScrollView, Text, StyleSheet } from 'react-native'; +import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; +import AppTopNavbar, { + APP_TOPBAR_TYPE_ENUM, +} from '../../../../components/shared/topnavbar/AppTopNavbar'; +import { APP_FONTS } from '../../../../styles/AppFonts'; +import { useAppTheme } from '../../../../hooks/utility/global-state-extractors'; + +function Page() { + const { translateY } = useScrollMoreOnPageEnd(); + const { theme } = useAppTheme(); + + return ( + + + + More settings coming{' '} + soon™ + + + + ); +} + +export default Page; + +const styles = StyleSheet.create({ + text: { + fontFamily: APP_FONTS.INTER_600_SEMIBOLD, + marginTop: '50%', + fontSize: 18, + textAlign: 'center', + }, +}); diff --git a/apps/mobile/app/(tabs)/profile/settings/app-settings.tsx b/apps/mobile/app/(tabs)/profile/settings/app-settings.tsx deleted file mode 100644 index bd21abbf..00000000 --- a/apps/mobile/app/(tabs)/profile/settings/app-settings.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import AppSettingsPage from '../../../../components/screens/profile/stack/AppSettingsPage'; - -function SettingsLanding() { - return ; -} - -export default SettingsLanding; diff --git a/apps/mobile/app/(tabs)/profile/settings/general.tsx b/apps/mobile/app/(tabs)/profile/settings/general.tsx new file mode 100644 index 00000000..811a0b73 --- /dev/null +++ b/apps/mobile/app/(tabs)/profile/settings/general.tsx @@ -0,0 +1,38 @@ +import { ScrollView, Text, StyleSheet } from 'react-native'; +import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; +import AppTopNavbar, { + APP_TOPBAR_TYPE_ENUM, +} from '../../../../components/shared/topnavbar/AppTopNavbar'; +import { APP_FONTS } from '../../../../styles/AppFonts'; +import { useAppTheme } from '../../../../hooks/utility/global-state-extractors'; + +function Page() { + const { translateY } = useScrollMoreOnPageEnd(); + const { theme } = useAppTheme(); + + return ( + + + + More settings coming{' '} + soon™ + + + + ); +} + +export default Page; + +const styles = StyleSheet.create({ + text: { + fontFamily: APP_FONTS.INTER_600_SEMIBOLD, + marginTop: '50%', + fontSize: 18, + textAlign: 'center', + }, +}); diff --git a/apps/mobile/app/(tabs)/profile/settings/goodie-hut.tsx b/apps/mobile/app/(tabs)/profile/settings/goodie-hut.tsx new file mode 100644 index 00000000..699f0aa9 --- /dev/null +++ b/apps/mobile/app/(tabs)/profile/settings/goodie-hut.tsx @@ -0,0 +1,38 @@ +import { ScrollView, Text, StyleSheet } from 'react-native'; +import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; +import AppTopNavbar, { + APP_TOPBAR_TYPE_ENUM, +} from '../../../../components/shared/topnavbar/AppTopNavbar'; +import { APP_FONTS } from '../../../../styles/AppFonts'; +import { useAppTheme } from '../../../../hooks/utility/global-state-extractors'; + +function Page() { + const { translateY } = useScrollMoreOnPageEnd(); + const { theme } = useAppTheme(); + + return ( + + + + More settings coming{' '} + soon™ + + + + ); +} + +export default Page; + +const styles = StyleSheet.create({ + text: { + fontFamily: APP_FONTS.INTER_600_SEMIBOLD, + marginTop: '50%', + fontSize: 18, + textAlign: 'center', + }, +}); diff --git a/apps/mobile/app/(tabs)/profile/settings/help.tsx b/apps/mobile/app/(tabs)/profile/settings/help.tsx deleted file mode 100644 index 25c54dea..00000000 --- a/apps/mobile/app/(tabs)/profile/settings/help.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { memo } from 'react'; -import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; -import AppTopNavbar, { - APP_TOPBAR_TYPE_ENUM, -} from '../../../../components/shared/topnavbar/AppTopNavbar'; -import { ScrollView, Text, TouchableOpacity, View } from 'react-native'; -import { APP_FONT } from '../../../../styles/AppTheme'; -import { APP_FONTS } from '../../../../styles/AppFonts'; -import * as Linking from 'expo-linking'; -import AntDesign from '@expo/vector-icons/AntDesign'; -import { Ionicons } from '@expo/vector-icons'; - -const SettingsStackHelp = memo(() => { - const { translateY } = useScrollMoreOnPageEnd(); - - return ( - - - - Will add more stuff here soon. - - - Mostly related to helpful links to the documentation website (yep, did - you not know that we have a wiki ???). - - - - { - Linking.openURL('https://discord.gg/kMp5JA9jwD'); - }} - > - - - - - Join on Discord - - - { - Linking.openURL('https://dhaaga.app/docs'); - }} - > - - - - - Open Wiki - - - - - - ); -}); - -export default SettingsStackHelp; diff --git a/apps/mobile/app/(tabs)/profile/settings/info.tsx b/apps/mobile/app/(tabs)/profile/settings/info.tsx deleted file mode 100644 index 96292f1d..00000000 --- a/apps/mobile/app/(tabs)/profile/settings/info.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { memo } from 'react'; -import AppTopNavbar, { - APP_TOPBAR_TYPE_ENUM, -} from '../../../../components/shared/topnavbar/AppTopNavbar'; -import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; -import { ScrollView, Text } from 'react-native'; -import { APP_FONT } from '../../../../styles/AppTheme'; -import { APP_FONTS } from '../../../../styles/AppFonts'; - -const SettingsStackInfo = memo(() => { - const { translateY } = useScrollMoreOnPageEnd(); - - return ( - - - - Will add more stuff here soon. - - - Mostly related to information about what the app does and various - project links. - - - - ); -}); - -export default SettingsStackInfo; diff --git a/apps/mobile/app/(tabs)/profile/settings/support.tsx b/apps/mobile/app/(tabs)/profile/settings/support.tsx deleted file mode 100644 index 0e7d6e2a..00000000 --- a/apps/mobile/app/(tabs)/profile/settings/support.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { memo } from 'react'; -import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; -import AppTopNavbar, { - APP_TOPBAR_TYPE_ENUM, -} from '../../../../components/shared/topnavbar/AppTopNavbar'; -import { ScrollView, Text, View } from 'react-native'; -import { APP_FONT } from '../../../../styles/AppTheme'; -import { APP_FONTS } from '../../../../styles/AppFonts'; -import Coffee from '../../../../components/static/sponsorship/Coffee'; - -const SettingsStackSupport = memo(() => { - const { translateY } = useScrollMoreOnPageEnd(); - - return ( - - - - If you think{' '} - - #DhaagaApp - {' '} - is pretty cool, Tell your friends about it! - - - - - If you really love the app, you can send me a tip! - - - - - - - (More ways to support my Indie journey long-term are available from - the project's website and GitHub.) - - - - - ); -}); - -export default SettingsStackSupport; diff --git a/apps/mobile/app/(tabs)/profile/settings/wellbeing.tsx b/apps/mobile/app/(tabs)/profile/settings/wellbeing.tsx index eed02bca..0be1f039 100644 --- a/apps/mobile/app/(tabs)/profile/settings/wellbeing.tsx +++ b/apps/mobile/app/(tabs)/profile/settings/wellbeing.tsx @@ -1,20 +1,38 @@ -import { memo } from 'react'; +import { ScrollView, Text, StyleSheet } from 'react-native'; +import AppTopNavbar, { + APP_TOPBAR_TYPE_ENUM, +} from '../../../../components/shared/topnavbar/AppTopNavbar'; +import { useAppTheme } from '../../../../hooks/utility/global-state-extractors'; import useScrollMoreOnPageEnd from '../../../../states/useScrollMoreOnPageEnd'; -import WithAutoHideTopNavBar from '../../../../components/containers/WithAutoHideTopNavBar'; -import Animated from 'react-native-reanimated'; +import { APP_FONTS } from '../../../../styles/AppFonts'; -const WellbeingSettingsPage = memo(() => { +function Page() { const { translateY } = useScrollMoreOnPageEnd(); + const { theme } = useAppTheme(); + return ( - - - + + + + More settings coming{' '} + soon™ + + + ); -}); +} -export default WellbeingSettingsPage; +export default Page; + +const styles = StyleSheet.create({ + text: { + fontFamily: APP_FONTS.INTER_600_SEMIBOLD, + marginTop: '50%', + fontSize: 18, + textAlign: 'center', + }, +}); diff --git a/apps/mobile/components/common/media/NotificationMediaThumbs.tsx b/apps/mobile/components/common/media/NotificationMediaThumbs.tsx index 4a1b5f70..2104302f 100644 --- a/apps/mobile/components/common/media/NotificationMediaThumbs.tsx +++ b/apps/mobile/components/common/media/NotificationMediaThumbs.tsx @@ -15,7 +15,9 @@ type ThumbItemProps = { function ThumbItem({ item, post, server }: ThumbItemProps) { const Data = useImageAutoHeight(item, 100, 200); - const isMastodonLike = ActivityPubService.mastodonLike(server); + // too resource expensive + // const isMastodonLike = ActivityPubService.mastodonLike(server); + if (!Data.resolved) return ; return ( @@ -32,7 +34,7 @@ function ThumbItem({ item, post, server }: ThumbItemProps) { justifyContent: 'center', }} source={{ - uri: isMastodonLike ? item.url : item.previewUrl, + uri: item.previewUrl, }} transition={{ effect: 'flip-from-right', diff --git a/apps/mobile/components/containers/SwipeableTabsContainer.tsx b/apps/mobile/components/containers/SwipeableTabsContainer.tsx index d256c5b8..b40dc9a3 100644 --- a/apps/mobile/components/containers/SwipeableTabsContainer.tsx +++ b/apps/mobile/components/containers/SwipeableTabsContainer.tsx @@ -1,8 +1,8 @@ import { View } from 'react-native'; import { useAppTheme } from '../../hooks/utility/global-state-extractors'; import { BottomNavBar } from '../shared/pager-view/BottomNavBar'; -import { useState } from 'react'; -import { AppPagerView } from '../lib/AppPagerView'; +import { useRef, useState } from 'react'; +import PagerView from 'react-native-pager-view'; type SwipeableTabsContainerProps = { pages: { label: string; id: string }[]; @@ -16,19 +16,32 @@ function SwipeableTabsContainer({ const [Index, setIndex] = useState(0); const { theme } = useAppTheme(); + const ref = useRef(null); const onChipSelect = (index: number) => { if (Index !== index) { - setIndex(index); + ref.current.setPage(index); } }; + function onPageScroll(e: any) { + const { offset, position } = e.nativeEvent; + const nextIdx = Math.round(position + offset); + setIndex(nextIdx); + } + return ( - + + {Array.from({ length: pages.length }).map((_, index) => ( + {renderScene(index)} + ))} + ); } + export default SwipeableTabsContainer; diff --git a/apps/mobile/components/containers/UserGuideContainer.tsx b/apps/mobile/components/containers/UserGuideContainer.tsx index 597124f0..4db14de6 100644 --- a/apps/mobile/components/containers/UserGuideContainer.tsx +++ b/apps/mobile/components/containers/UserGuideContainer.tsx @@ -1,6 +1,4 @@ import useScrollMoreOnPageEnd from '../../states/useScrollMoreOnPageEnd'; -import useGlobalState from '../../states/_global'; -import { useShallow } from 'zustand/react/shallow'; import { ScrollView, StyleProp, @@ -13,6 +11,7 @@ import { APP_FONTS } from '../../styles/AppFonts'; import AppTopNavbar, { APP_TOPBAR_TYPE_ENUM, } from '../shared/topnavbar/AppTopNavbar'; +import { useAppTheme } from '../../hooks/utility/global-state-extractors'; type UserGuideContainerProps = { questionnaire: { question: string; answers: string[] }[]; @@ -22,11 +21,7 @@ type UserGuideContainerProps = { function UserGuideContainer({ questionnaire, label }: UserGuideContainerProps) { const { translateY } = useScrollMoreOnPageEnd({}); - const { theme } = useGlobalState( - useShallow((o) => ({ - theme: o.colorScheme, - })), - ); + const { theme } = useAppTheme(); const sectionStyle: StyleProp = { marginBottom: 16, diff --git a/apps/mobile/components/dhaaga-bottom-sheet/modules/select-account/AppBottomSheetSelectAccount.tsx b/apps/mobile/components/dhaaga-bottom-sheet/modules/select-account/AppBottomSheetSelectAccount.tsx index 666f8233..56ea3716 100644 --- a/apps/mobile/components/dhaaga-bottom-sheet/modules/select-account/AppBottomSheetSelectAccount.tsx +++ b/apps/mobile/components/dhaaga-bottom-sheet/modules/select-account/AppBottomSheetSelectAccount.tsx @@ -140,7 +140,7 @@ const AppBottomSheetSelectAccount = memo(() => { function onPressMoreAccountOptions() { hide(); - router.navigate(APP_ROUTING_ENUM.PROFILE_ACCOUNTS); + router.navigate(APP_ROUTING_ENUM.SETTINGS_TAB_ACCOUNTS); } return ( diff --git a/apps/mobile/components/error-screen/AppNoAccount.tsx b/apps/mobile/components/error-screen/AppNoAccount.tsx index ff91c4c0..a571f70f 100644 --- a/apps/mobile/components/error-screen/AppNoAccount.tsx +++ b/apps/mobile/components/error-screen/AppNoAccount.tsx @@ -41,7 +41,7 @@ export function DriverSelectionFragment() { to: string; }[] = [ { - label: 'Bluesky', + label: 'Bluesky (⛔, 🚧)', padding: 0, rightComponent: ( (null); - const [Index, setIndex] = useState(0); - function onPageScroll(e: any) { const { offset, position } = e.nativeEvent; const nextIdx = Math.round(position + offset); - setIndex(nextIdx); if (onPageChangeCallback) onPageChangeCallback(nextIdx); } @@ -28,7 +25,7 @@ export function AppPagerView({ ref={ref} scrollEnabled={true} style={styles.pagerView} - initialPage={Index} + initialPage={0} onPageScroll={onPageScroll} > {Array.from({ length: pageCount }).map((_, index) => ( diff --git a/apps/mobile/components/screens/home/SocialHub.tsx b/apps/mobile/components/screens/home/SocialHub.tsx index ae409b00..00dbeb68 100644 --- a/apps/mobile/components/screens/home/SocialHub.tsx +++ b/apps/mobile/components/screens/home/SocialHub.tsx @@ -100,7 +100,7 @@ function SocialHubTabAdd() { }, ]} onPress={() => { - router.navigate(APP_ROUTING_ENUM.PROFILE_ACCOUNTS); + router.navigate(APP_ROUTING_ENUM.SETTINGS_TAB_ACCOUNTS); }} > ; case DhaagaJsNotificationType.MENTION: + case DhaagaJsNotificationType.CHAT: return ; case DhaagaJsNotificationType.FAVOURITE: return ; diff --git a/apps/mobile/components/screens/notifications/landing/fragments/NotificationSender.tsx b/apps/mobile/components/screens/notifications/landing/fragments/NotificationSender.tsx index 9759d195..68a327bf 100644 --- a/apps/mobile/components/screens/notifications/landing/fragments/NotificationSender.tsx +++ b/apps/mobile/components/screens/notifications/landing/fragments/NotificationSender.tsx @@ -22,6 +22,7 @@ import { useAppTheme, } from '../../../../../hooks/utility/global-state-extractors'; import { LocalizationService } from '../../../../../services/localization.service'; +import useMfm from '../../../../hooks/useMfm'; type Props = { type: DhaagaJsNotificationType; @@ -50,6 +51,14 @@ export const NotificationSender = memo( }: Props) => { const { theme } = useAppTheme(); + // const { content: _displayName } = useMfm({ + // content: displayName, + // remoteSubdomain, + // emojiMap: new Map(), + // deps: [displayName], + // fontFamily: APP_FONTS.MONTSERRAT_700_BOLD, + // }); + const { find } = useAppCustomEmoji(); const { Icon, bg } = useMemo(() => { switch (type) { @@ -185,7 +194,7 @@ export const NotificationSender = memo( }, [type, extraData]); return ( - + {/*@ts-ignore-next-line*/} - - {displayName} - + + {displayName} + + - + ); }, diff --git a/apps/mobile/components/screens/notifications/landing/segments/BoostNotificationFragment.tsx b/apps/mobile/components/screens/notifications/landing/segments/BoostNotificationFragment.tsx index b9a84309..c5cdcc8f 100644 --- a/apps/mobile/components/screens/notifications/landing/segments/BoostNotificationFragment.tsx +++ b/apps/mobile/components/screens/notifications/landing/segments/BoostNotificationFragment.tsx @@ -4,6 +4,7 @@ import { DhaagaJsNotificationType } from '@dhaaga/bridge'; import { View } from 'react-native'; import { NotificationSenderInterface } from '../fragments/NotificationSender'; import { NotificationPostPeek } from '../fragments/NotificationPostPeek'; +import { AppDivider } from '../../../../lib/Divider'; const BoostNotificationFragment = memo(function Foo({ item }: Props) { const user = item.user; @@ -17,6 +18,7 @@ const BoostNotificationFragment = memo(function Foo({ item }: Props) { createdAt={item.createdAt} /> + ); }); diff --git a/apps/mobile/components/screens/notifications/landing/segments/FavouriteNotificationFragment.tsx b/apps/mobile/components/screens/notifications/landing/segments/FavouriteNotificationFragment.tsx index 38025ef6..d33e28e1 100644 --- a/apps/mobile/components/screens/notifications/landing/segments/FavouriteNotificationFragment.tsx +++ b/apps/mobile/components/screens/notifications/landing/segments/FavouriteNotificationFragment.tsx @@ -3,8 +3,8 @@ import { Props, styles } from './_common'; import { View } from 'react-native'; import { DhaagaJsNotificationType } from '@dhaaga/bridge'; import { NotificationSenderInterface } from '../fragments/NotificationSender'; -import { NotificationDescriptionText } from '../fragments/NotificationDescriptionText'; import { NotificationPostPeek } from '../fragments/NotificationPostPeek'; +import { AppDivider } from '../../../../lib/Divider'; const FavouriteNotificationFragment = memo(function Foo({ item }: Props) { const user = item.user; @@ -17,12 +17,8 @@ const FavouriteNotificationFragment = memo(function Foo({ item }: Props) { type={DhaagaJsNotificationType.FAVOURITE} createdAt={item.createdAt} /> - + ); }); diff --git a/apps/mobile/components/screens/notifications/landing/segments/MentionNotificationFragment.tsx b/apps/mobile/components/screens/notifications/landing/segments/MentionNotificationFragment.tsx index 8f3ecac1..16a6fc72 100644 --- a/apps/mobile/components/screens/notifications/landing/segments/MentionNotificationFragment.tsx +++ b/apps/mobile/components/screens/notifications/landing/segments/MentionNotificationFragment.tsx @@ -10,7 +10,6 @@ const MentionNotificationFragment = memo(({ item }: Props) => { const user = item.user; const post = item.post; - console.log(post.calculated.emojis); return ( { }, ]} tabType={APP_LANDING_PAGE_TYPE.CHAT} - tip={'Chat has not been implemented in Dhaaga yet.'} + tip={ + 'Not implemented yet.\n\nNotifications are shared with Mention tab for now!' + } onRefresh={refetch} /> ); diff --git a/apps/mobile/components/screens/notifications/landing/views/MentionView.tsx b/apps/mobile/components/screens/notifications/landing/views/MentionView.tsx index 6a8d22df..5225a8d3 100644 --- a/apps/mobile/components/screens/notifications/landing/views/MentionView.tsx +++ b/apps/mobile/components/screens/notifications/landing/views/MentionView.tsx @@ -1,10 +1,19 @@ -import { memo } from 'react'; +import { memo, useState } from 'react'; import { APP_LANDING_PAGE_TYPE } from '../../../../shared/topnavbar/AppTabLandingNavbar'; import AppNotificationViewContainer from './_container'; -import { useApiGetSocialUpdates } from '../../../../../hooks/api/useNotifications'; +import { useApiGetMentionUpdates } from '../../../../../hooks/api/useNotifications'; const MentionView = memo(() => { - const { data } = useApiGetSocialUpdates(); + const [IsRefreshing, setIsRefreshing] = useState(false); + const { data, refetch } = useApiGetMentionUpdates(); + + function refresh() { + setIsRefreshing(true); + refetch().finally(() => { + setIsRefreshing(false); + }); + } + return ( { tabType={APP_LANDING_PAGE_TYPE.MENTIONS} tip={'These users have mentioned or replied to you.'} data={data.data} + refreshing={IsRefreshing} + onRefresh={refresh} /> ); }); diff --git a/apps/mobile/components/screens/notifications/landing/views/SocialView.tsx b/apps/mobile/components/screens/notifications/landing/views/SocialView.tsx index 8787e58d..49628a63 100644 --- a/apps/mobile/components/screens/notifications/landing/views/SocialView.tsx +++ b/apps/mobile/components/screens/notifications/landing/views/SocialView.tsx @@ -1,14 +1,22 @@ -import { memo } from 'react'; +import { memo, useState } from 'react'; import AppNotificationViewContainer from './_container'; import { APP_LANDING_PAGE_TYPE } from '../../../../shared/topnavbar/AppTabLandingNavbar'; import { useApiGetSocialUpdates } from '../../../../../hooks/api/useNotifications'; const SocialView = memo(() => { - const { data } = useApiGetSocialUpdates(); + const [IsRefreshing, setIsRefreshing] = useState(false); + const { data, refetch } = useApiGetSocialUpdates(); + + function refresh() { + setIsRefreshing(true); + refetch().finally(() => { + setIsRefreshing(false); + }); + } return ( { iconId: 'user-guide', }, ]} - tip={'These are updates from accounts you follow.'} + tip={'These people have liked, shared and reacted to your posts.'} + refreshing={IsRefreshing} + onRefresh={refresh} /> ); }); diff --git a/apps/mobile/components/screens/notifications/landing/views/UpdatesView.tsx b/apps/mobile/components/screens/notifications/landing/views/UpdatesView.tsx index d1f59eb7..fab1c393 100644 --- a/apps/mobile/components/screens/notifications/landing/views/UpdatesView.tsx +++ b/apps/mobile/components/screens/notifications/landing/views/UpdatesView.tsx @@ -1,14 +1,14 @@ import { memo } from 'react'; import { APP_LANDING_PAGE_TYPE } from '../../../../shared/topnavbar/AppTabLandingNavbar'; import AppNotificationViewContainer from './_container'; -import { useApiGetSocialUpdates } from '../../../../../hooks/api/useNotifications'; +import { useApiGetSubscriptionUpdates } from '../../../../../hooks/api/useNotifications'; const UpdatesView = memo(() => { - const { data } = useApiGetSocialUpdates(); + const { data } = useApiGetSubscriptionUpdates(); return ( { iconId: 'user-guide', }, ]} - tip={'These are updates from accounts you follow.'} + tip={'These are updates from accounts you have subscribed to.'} /> ); }); diff --git a/apps/mobile/components/screens/notifications/landing/views/_container.tsx b/apps/mobile/components/screens/notifications/landing/views/_container.tsx index a64eae92..8ad473db 100644 --- a/apps/mobile/components/screens/notifications/landing/views/_container.tsx +++ b/apps/mobile/components/screens/notifications/landing/views/_container.tsx @@ -71,7 +71,7 @@ const styles = StyleSheet.create({ tipText: { fontSize: 14, fontFamily: APP_FONTS.INTER_500_MEDIUM, - textAlign: 'left', + textAlign: 'center', marginHorizontal: 10, marginBottom: 16, }, diff --git a/apps/mobile/components/screens/profile/stack/AppSettingsPage.tsx b/apps/mobile/components/screens/profile/stack/AppSettingsPage.tsx index e25ee970..2522252e 100644 --- a/apps/mobile/components/screens/profile/stack/AppSettingsPage.tsx +++ b/apps/mobile/components/screens/profile/stack/AppSettingsPage.tsx @@ -243,68 +243,76 @@ function SettingCategoryList() { const { theme } = useAppTheme(); const SETTING_CATEGORY_ICON_COLOR = theme.primary.a10; + const items = [ + { + label: 'Accounts', + desc: 'Add and Manage Accounts', + Icon: ( + + ), + to: APP_ROUTING_ENUM.SETTINGS_TAB_ACCOUNTS, + }, + { + label: 'General', + desc: 'Most usual boring settings are here', + Icon: ( + + ), + to: APP_ROUTING_ENUM.SETTINGS_TAB_GENERAL, + }, + { + label: 'Goodie Hut', + desc: 'Tweak unique features of Dhaaga', + Icon: ( + + ), + to: APP_ROUTING_ENUM.SETTINGS_TAB_GOODIE_HUT, + }, + { + label: 'Digital Wellbeing', + desc: 'Disconnect to reconnect with yourself', + Icon: ( + + ), + to: APP_ROUTING_ENUM.SETTINGS_TAB_DIGITAL_WELLBEING, + }, + { + label: 'Advanced', + desc: 'For power users', + Icon: ( + + ), + to: APP_ROUTING_ENUM.SETTINGS_TAB_ADVANCED, + }, + ]; + return ( - - } - desc={'Add and Manage Accounts'} - /> - - } - /> - - } - /> - - } - /> - - } - /> + {items.map((o, i) => ( + + ))} ); } diff --git a/apps/mobile/components/screens/profile/stack/SelectAccount.tsx b/apps/mobile/components/screens/profile/stack/SelectAccount.tsx index 790f1885..754dcf0c 100644 --- a/apps/mobile/components/screens/profile/stack/SelectAccount.tsx +++ b/apps/mobile/components/screens/profile/stack/SelectAccount.tsx @@ -1,5 +1,11 @@ -import { FlatList, RefreshControl, View, Text } from 'react-native'; -import { Button } from '@rneui/base'; +import { + FlatList, + RefreshControl, + View, + Text, + Pressable, + StyleSheet, +} from 'react-native'; import { router } from 'expo-router'; import { useEffect, useState } from 'react'; import { KNOWN_SOFTWARE } from '@dhaaga/bridge'; @@ -19,6 +25,7 @@ import { } from '../../../../hooks/utility/global-state-extractors'; import { APP_EVENT_ENUM } from '../../../../services/publishers/app.publisher'; import { APP_ROUTING_ENUM } from '../../../../utils/route-list'; +import { appDimensions } from '../../../../styles/dimensions'; function SelectAccountStack() { const { theme } = useAppTheme(); @@ -76,7 +83,7 @@ function SelectAccountStack() { return ( @@ -91,30 +98,28 @@ function SelectAccountStack() { backgroundColor: theme.palette.bg, }} ListFooterComponent={ - - + + + Add Account + - Mastodon, Pleroma, Akkoma, Misskey, Firefish, Sharkey + Bluesky, Mastodon, Misskey, Pleroma, Akkoma, Sharkey, Firefish + (Legacy) } @@ -127,3 +132,28 @@ function SelectAccountStack() { } export default SelectAccountStack; + +const styles = StyleSheet.create({ + footerContainer: { + marginHorizontal: 16, + marginBottom: 32, + marginTop: 72, + }, + ctaButtonContainer: { + borderRadius: appDimensions.buttons.borderRadius, + padding: 8, + }, + ctaButtonText: { + color: 'black', + fontFamily: APP_FONTS.INTER_600_SEMIBOLD, + fontSize: 16, + textAlign: 'center', + }, + tipText: { + fontFamily: APP_FONTS.INTER_500_MEDIUM, + textAlign: 'center', + marginTop: 16, + paddingHorizontal: 16, + fontSize: 14, + }, +}); diff --git a/apps/mobile/components/screens/profile/stack/onboard/fragments/PleromaPasteToken.tsx b/apps/mobile/components/screens/profile/stack/onboard/fragments/PleromaPasteToken.tsx index 3728d7e4..f4508c0c 100644 --- a/apps/mobile/components/screens/profile/stack/onboard/fragments/PleromaPasteToken.tsx +++ b/apps/mobile/components/screens/profile/stack/onboard/fragments/PleromaPasteToken.tsx @@ -22,7 +22,7 @@ const PleromaPasteToken = memo( return ; return ( - + ({ - client: o.router, - acct: o.acct, - driver: o.driver, - })), - ); + const { acct } = useAppAcct(); + const { client, driver } = useAppApiClient(); async function api(): Promise { if (!client) throw new Error('no client found'); @@ -62,8 +74,7 @@ function useApiGetNotifications({ include }: useApiGetNotificationsProps) { if (error) throw new Error(error.message); return { - data: NotificationMiddleware.deserialize( - // ignore certain notification types + data: NotificationMiddleware.deserialize( // ignore certain notification types data.data.filter((o) => ['login'].includes(o.type)), driver, acct?.server, @@ -77,11 +88,11 @@ function useApiGetNotifications({ include }: useApiGetNotificationsProps) { excludeTypes: [], types: include, }); + if (error) throw new Error(error.message); return { - data: NotificationMiddleware.deserialize( - // ignore certain notification types - data.data.filter((o) => ['login'].includes(o.type)), + data: NotificationMiddleware.deserialize( // ignore certain notification types + data.data, driver, acct?.server, ), @@ -100,6 +111,98 @@ function useApiGetNotifications({ include }: useApiGetNotificationsProps) { }); } +/** + * Get Mentions + * + * - Grouped for Mastodon + */ +function useApiGetMentionUpdates() { + const { acct } = useAppAcct(); + const { driver, client, server } = useAppApiClient(); + + async function api(): Promise { + const results = await client.notifications.getMentions(driver); + if (results.error) { + throw new Error(results.error.message); + } else { + const _data = results.data; + if (ActivityPubService.misskeyLike(driver)) { + return { + data: _data.data.map((o: any) => { + const _acct = UserMiddleware.deserialize( + o.user, + driver, + server, + ); + const _post = PostMiddleware.deserialize( + o, + driver, + server, + ); + const _obj: AppNotificationObject = { + id: RandomUtil.nanoId(), + type: _post.visibility === 'specified' ? 'chat' : 'mention', + post: _post, + user: _acct, + read: false, + createdAt: new Date(_post.createdAt), + extraData: {}, + }; + return _obj; + }), + minId: null, + maxId: null, + }; + } + + const acctList = _data.data.accounts; + const postList = _data.data.statuses; + const _retval = _data.data.notificationGroups + .map((o: MastoGroupedNotificationType) => { + const _acct = UserMiddleware.deserialize( + acctList.find((x) => x.id === o.sampleAccountIds[0]), + driver, + server, + ); + const _post = PostMiddleware.deserialize( + postList.find((x) => x.id === o.statusId), + driver, + server, + ); + + // bring this back when chat is implemented + // if (o.type === 'mention' && _post.visibility === 'direct') + // return null; + const _obj: AppNotificationObject = { + id: o.groupKey, + type: o.type, + post: _post, + user: _acct, + read: false, + createdAt: new Date(o.mostRecentNotificationId), + extraData: {}, + }; + return _obj; + }) + .filter((o) => !!o); + + return { + data: _retval, + maxId: _data.maxId, + minId: _data.minId, + }; + } + } + + // Queries + return useQuery({ + queryKey: ['notifications/mentions', acct], + queryFn: api, + enabled: client !== null, + initialData: defaultHookResult, + }); +} + /** * Fetches direct message data */ @@ -119,7 +222,6 @@ function useApiGetChatUpdates() { case KNOWN_SOFTWARE.SHARKEY: { const chatResult = await client.notifications.getChats(driver); if (chatResult.error) { - console.log(chatResult); return null; } else { return chatResult.data; @@ -155,7 +257,112 @@ function useApiGetChatUpdates() { } function useApiGetSocialUpdates() { - const { appendNotifs } = useAppNotifSeenContext(); + const { acct } = useAppAcct(); + const { driver, client, server } = useAppApiClient(); + + async function api(): Promise { + const results = await client.notifications.getSocialUpdates({ + limit: 40, + excludeTypes: [], + types: [], + }); + if (results.error) { + throw new Error(results.error.message); + } else { + const _data = results.data; + if (ActivityPubService.misskeyLike(driver)) { + return { + data: _data.data.map((o: any) => { + const _acct = UserMiddleware.deserialize( + o.user, + driver, + server, + ); + const _post = PostMiddleware.deserialize( + o, + driver, + server, + ); + const _obj: AppNotificationObject = { + id: RandomUtil.nanoId(), + type: _post.visibility === 'specified' ? 'chat' : 'mention', + post: _post, + user: _acct, + read: false, + createdAt: new Date(_post.createdAt), + extraData: {}, + }; + return _obj; + }), + minId: null, + maxId: null, + }; + } + + const acctList = _data.data.accounts; + const postList = _data.data.statuses; + const _retval = _data.data.notificationGroups + .map((o: MastoGroupedNotificationType) => { + const _acct = UserMiddleware.deserialize( + acctList.find((x) => x.id === o.sampleAccountIds[0]), + driver, + server, + ); + const _post = PostMiddleware.deserialize( + postList.find((x) => x.id === o.statusId), + driver, + server, + ); + + // bring this back when chat is implemented + // if (o.type === 'mention' && _post.visibility === 'direct') + // return null; + const _obj: AppNotificationObject = { + id: o.groupKey, + type: o.type, + post: _post, + user: _acct, + read: false, + createdAt: new Date(o.mostRecentNotificationId), + extraData: {}, + }; + return _obj; + }) + .filter((o) => !!o) + .filter((o) => !['mention'].includes(o.type)); + + return { + data: _retval, + maxId: _data.maxId, + minId: _data.minId, + }; + } + } + + // const { driver } = useAppApiClient(); + // const { data } = useApiGetNotifications({ + // include: ActivityPubService.mastodonLike(driver) + // ? [ + // // Mastodon + // DhaagaJsNotificationType.FAVOURITE, + // DhaagaJsNotificationType.POLL_ENDED, + // DhaagaJsNotificationType.POLL_NOTIFICATION, + // DhaagaJsNotificationType.POLL_VOTE, + // DhaagaJsNotificationType.REBLOG, + // ] + // : [], + // }); + + // Queries + return useQuery({ + queryKey: ['notifications/social', acct], + queryFn: api, + enabled: client !== null, + initialData: defaultHookResult, + }); +} + +function useApiGetSubscriptionUpdates() { const { data } = useApiGetNotifications({ include: [ // Mastodon @@ -165,11 +372,18 @@ function useApiGetSocialUpdates() { ], }); - useEffect(() => { - appendNotifs(data.data.map((o) => o.id)); - }, [data]); - - return { data }; + return { + data: { + data: data.data.filter((o) => ['note', 'renote'].includes(o.type)), + maxId: data.maxId, + minId: data.minId, + }, + }; } -export { useApiGetSocialUpdates, useApiGetChatUpdates }; +export { + useApiGetMentionUpdates, + useApiGetSocialUpdates, + useApiGetChatUpdates, + useApiGetSubscriptionUpdates, +}; diff --git a/apps/mobile/hooks/app/timelines/useAppTimelinePosts.tsx b/apps/mobile/hooks/app/timelines/useAppTimelinePosts.tsx index 8a8e18dd..72f6649c 100644 --- a/apps/mobile/hooks/app/timelines/useAppTimelinePosts.tsx +++ b/apps/mobile/hooks/app/timelines/useAppTimelinePosts.tsx @@ -10,7 +10,7 @@ import { } from 'react'; import ActivityPubService from '../../../services/activitypub.service'; import * as Haptics from 'expo-haptics'; -import { OpenAiService } from '../../../services/openai.service'; +import { HuggingFaceService } from '../../../services/openai.service'; import postArrayReducer, { TIMELINE_POST_LIST_DATA_REDUCER_TYPE, TimelineDataReducerFunction, @@ -230,7 +230,9 @@ function WithAppTimelineDataContext({ children }: Props) { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy).then(() => {}); setLoading(true); try { - const response = await OpenAiService.explain(ctx.join(',')); + const response = await HuggingFaceService.inferServerless( + ctx.join(','), + ); postListReducer({ type: TIMELINE_POST_LIST_DATA_REDUCER_TYPE.UPDATE_TRANSLATION_OUTPUT, payload: { diff --git a/apps/mobile/package.json b/apps/mobile/package.json index ed22f35f..13a2fb30 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -9,7 +9,7 @@ "aab": "eas build -p android --profile aab", "client": "eas build -p android --profile dev", "lite": "react-native build-android --mode=release && cd android && ./gradlew assembleRelease", - "postinstall": "cd ../.. && yarn build" + "postins tall": "cd ../.. && yarn build" }, "dependencies": { "@atproto/api": "^0.13.23", @@ -19,6 +19,7 @@ "@expo-google-fonts/montserrat": "^0.2.3", "@expo/metro-config": "~0.19.0", "@expo/vector-icons": "^14.0.4", + "@huggingface/inference": "^2.8.1", "@rneui/base": "^4.0.0-rc.7", "@rneui/themed": "^4.0.0-rc.8", "@shopify/flash-list": "1.7.1", @@ -29,7 +30,7 @@ "expo-build-properties": "~0.13.1", "expo-clipboard": "~7.0.0", "expo-constants": "~17.0.3", - "expo-dev-client": "~5.0.7", + "expo-dev-client": "~5.0.8", "expo-font": "~13.0.2", "expo-haptics": "~14.0.0", "expo-image": "~2.0.3", @@ -38,9 +39,8 @@ "expo-localization": "^16.0.0", "expo-notifications": "~0.29.11", "expo-router": "~4.0.15", - "expo-sharing": "~13.0.0", "expo-splash-screen": "~0.29.18", - "expo-sqlite": "~15.0.4", + "expo-sqlite": "~15.0.5", "expo-video": "~2.0.3", "fast-text-encoding": "^1.0.6", "i18n-js": "^4.4.3", @@ -48,7 +48,6 @@ "immer": "^10.1.1", "link-preview-js": "^3.0.12", "misskey-js": "^2024.11.1-alpha.0", - "openai": "^4.76.3", "react": "18.3.1", "react-i18next": "^15.2.0", "react-native": "0.76.5", diff --git a/apps/mobile/services/activitypub.service.ts b/apps/mobile/services/activitypub.service.ts index c1703258..ece5ffb8 100644 --- a/apps/mobile/services/activitypub.service.ts +++ b/apps/mobile/services/activitypub.service.ts @@ -279,11 +279,12 @@ class ActivityPubService { * @param mngr */ static async signInUrl(urlLike: string, mngr: AppSessionManager) { + console.log(urlLike); const tokens = mngr.storage.getAtprotoServerClientTokens(urlLike); const client = new UnknownRestClient(); const { data, error } = await client.instances.getLoginUrl(urlLike, { - appCallback: 'https://example.com/', + appCallback: 'https://suvam.io/dhaaga', appName: 'Dhaaga', appClientId: tokens?.clientId, appClientSecret: tokens?.clientSecret, diff --git a/apps/mobile/services/middlewares/notification.middleware.ts b/apps/mobile/services/middlewares/notification.middleware.ts index 065c2949..b00cdad0 100644 --- a/apps/mobile/services/middlewares/notification.middleware.ts +++ b/apps/mobile/services/middlewares/notification.middleware.ts @@ -21,6 +21,24 @@ export class NotificationMiddleware { driver: string | KNOWN_SOFTWARE, server: string, ): AppNotificationObject { + if (driver === KNOWN_SOFTWARE.MASTODON) { + return { + id: input.id, + type: + input['visibility'] === 'direct' + ? DhaagaJsNotificationType.CHAT + : DhaagaJsNotificationType.MENTION, + createdAt: input.createdAt, + user: UserMiddleware.deserialize( + input.account, + driver, + server, + ), + post: PostMiddleware.deserialize(input, driver, server), + extraData: {}, + read: false, + }; + } const obj = { id: input.id, type: input.type as DhaagaJsNotificationType, diff --git a/apps/mobile/services/openai.service.ts b/apps/mobile/services/openai.service.ts index a75e402f..d9701f88 100644 --- a/apps/mobile/services/openai.service.ts +++ b/apps/mobile/services/openai.service.ts @@ -1,25 +1,12 @@ -import OpenAI from 'openai'; +import { HfInference } from '@huggingface/inference'; -export class OpenAiService { - static async explain(input: string) { - if ( - !process.env.EXPO_PUBLIC_OPENAI_API_KEY || - process.env.EXPO_PUBLIC_OPENAI_API_KEY === '' - ) { - return ( - 'The lite edition of Dhaaga does not support AI features.' + - " Single tap the translation button to use your instance's" + - ' translation, instead (WIP).' - ); - } - try { - const client = new OpenAI({ - apiKey: process.env.EXPO_PUBLIC_OPENAI_API_KEY, - dangerouslyAllowBrowser: true, - }); +export class HuggingFaceService { + private static async _infer(input: string, token: string) { + const client = new HfInference(token); - const response = await client.chat.completions.create({ - model: 'gpt-3.5-turbo', + try { + const chatCompletion = await client.chatCompletion({ + model: 'meta-llama/Llama-2-7b-chat-hf', messages: [ { role: 'system', @@ -31,14 +18,24 @@ export class OpenAiService { role: 'user', content: input, }, + + { + role: 'user', + content: 'What is the capital of France?', + }, ], + max_tokens: 500, }); - for (let i = 0; i < response?.choices.length; i++) { - console.log(response?.choices[i].message); - } - return response?.choices[0].message.content; + console.log(chatCompletion.choices[0].message); } catch (e) { - console.log('error', e); + return null; } } + static async inferServerless(input: string): Promise { + return this._infer(input, 'N/A'); + } + + static async inferDedicated(input: string): Promise { + return this._infer(input, 'N/A'); + } } diff --git a/apps/mobile/services/session/_shared.ts b/apps/mobile/services/session/_shared.ts index 0d1b93df..09978a6a 100644 --- a/apps/mobile/services/session/_shared.ts +++ b/apps/mobile/services/session/_shared.ts @@ -1,4 +1,10 @@ import Storage from 'expo-sqlite/kv-store'; +import { z } from 'zod'; + +const savedObjectWithExpiry = z.object({ + updatedAt: z.date({ coerce: true }), + value: z.any(), +}); /** * Provides basic data storage/retrieval @@ -38,4 +44,23 @@ export class BaseStorageManager { setJson(key: string, value: any) { this.set(key, JSON.stringify(value)); } + + setJsonWithExpiry(key: string, value: any) { + this.set(key, JSON.stringify({ updatedAt: new Date(), value })); + } + + getJsonWithExpiry(key: string, invalidAfter: Date): T | null { + const saved = this.get(key); + if (!saved) return null; + + try { + const parsed = JSON.parse(saved); + const { success, error, data } = savedObjectWithExpiry.safeParse(parsed); + if (error) return null; + if (data.updatedAt < invalidAfter) return null; + return data.value; + } catch (e) { + return null; + } + } } diff --git a/apps/mobile/services/session/app-session.service.ts b/apps/mobile/services/session/app-session.service.ts index 672d0db7..7b5d3cd5 100644 --- a/apps/mobile/services/session/app-session.service.ts +++ b/apps/mobile/services/session/app-session.service.ts @@ -125,11 +125,16 @@ class Storage extends BaseStorageManager { */ getAtprotoServerClientTokens(server: string) { - return this.getJson( + // Get the current date and time + const sixHoursBefore = new Date(); + sixHoursBefore.setHours(sixHoursBefore.getHours() - 6); + + return this.getJsonWithExpiry( APP_CACHE_KEY.SERVER_CLIENT_TOKEN_TARGET.toString().replace( - '{:server}', + ':server', server, ), + sixHoursBefore, ); } @@ -138,9 +143,9 @@ class Storage extends BaseStorageManager { clientId: string, clientSecret: string, ) { - this.setJson( + this.setJsonWithExpiry( APP_CACHE_KEY.SERVER_CLIENT_TOKEN_TARGET.toString().replace( - '{:server}', + ':server', server, ), { diff --git a/apps/mobile/utils/route-list.ts b/apps/mobile/utils/route-list.ts index 17986aa2..00f8fa59 100644 --- a/apps/mobile/utils/route-list.ts +++ b/apps/mobile/utils/route-list.ts @@ -1,5 +1,4 @@ export enum APP_ROUTING_ENUM { - PROFILE_ACCOUNTS = '/profile/accounts', MISSKEY_SIGNIN = '/profile/onboard/signin-mk', MISSKEY_SERVER_SELECTION = '/profile/onboard/add-misskey', MASTODON_SIGNIN = '/profile/onboard/signin-md', @@ -12,4 +11,11 @@ export enum APP_ROUTING_ENUM { GUIDE_SETTINGS_TAB = '/profile/user-guide-settings', SELECT_DRIVER = '/profile/pick-driver', + + // Settings Modules + SETTINGS_TAB_ACCOUNTS = '/profile/settings/accounts', + SETTINGS_TAB_GENERAL = '/profile/settings/general', + SETTINGS_TAB_GOODIE_HUT = '/profile/settings/goodie-hut', + SETTINGS_TAB_DIGITAL_WELLBEING = '/profile/settings/digital-wellbeing', + SETTINGS_TAB_ADVANCED = '/profile/settings/advanced', } diff --git a/packages/bridge/src/adapters/_client/_router/routes/notifications.ts b/packages/bridge/src/adapters/_client/_router/routes/notifications.ts index f29e5340..58ad121f 100644 --- a/packages/bridge/src/adapters/_client/_router/routes/notifications.ts +++ b/packages/bridge/src/adapters/_client/_router/routes/notifications.ts @@ -4,6 +4,7 @@ import { MastoNotification } from '../../../../types/mastojs.types.js'; import { MegaNotification } from '../../../../types/megalodon.types.js'; export enum DhaagaJsNotificationType { + CHAT = 'chat', // direct /** * Someone mentioned you in their status */ @@ -88,6 +89,7 @@ export interface NotificationsRoute { getMentions(driver: KNOWN_SOFTWARE): LibraryPromise; getChats(driver: KNOWN_SOFTWARE): LibraryPromise; + getSocialUpdates(query: NotificationGetQueryDto): LibraryPromise; // e,g. of how to get new notifs // https://blob.cat/api/v1/notifications?since_id=2455610&with_muted=true&limit=20 diff --git a/packages/bridge/src/adapters/_client/bluesky/notifications.ts b/packages/bridge/src/adapters/_client/bluesky/notifications.ts index 182d5583..dd78d292 100644 --- a/packages/bridge/src/adapters/_client/bluesky/notifications.ts +++ b/packages/bridge/src/adapters/_client/bluesky/notifications.ts @@ -25,6 +25,10 @@ class BlueskyNotificationsRouter implements NotificationsRoute { async getMentions() { return notImplementedErrorBuilder(); } + + async getSocialUpdates(query: NotificationGetQueryDto) { + return notImplementedErrorBuilder(); + } } export default BlueskyNotificationsRouter; diff --git a/packages/bridge/src/adapters/_client/default/notifications.ts b/packages/bridge/src/adapters/_client/default/notifications.ts index cca63b33..a29033d6 100644 --- a/packages/bridge/src/adapters/_client/default/notifications.ts +++ b/packages/bridge/src/adapters/_client/default/notifications.ts @@ -1,4 +1,7 @@ -import { NotificationsRoute } from '../_router/routes/notifications.js'; +import { + NotificationGetQueryDto, + NotificationsRoute, +} from '../_router/routes/notifications.js'; import { notImplementedErrorBuilder } from '../_router/dto/api-responses.dto.js'; import { MastoNotification } from '../../../types/mastojs.types.js'; import { LibraryResponse } from '../../../types/result.types.js'; @@ -25,4 +28,8 @@ export class DefaultNotificationsRouter implements NotificationsRoute { async getMentions() { return notImplementedErrorBuilder(); } + + async getSocialUpdates(query: NotificationGetQueryDto) { + return notImplementedErrorBuilder(); + } } diff --git a/packages/bridge/src/adapters/_client/mastodon/notifications.ts b/packages/bridge/src/adapters/_client/mastodon/notifications.ts index 690dc672..598426c3 100644 --- a/packages/bridge/src/adapters/_client/mastodon/notifications.ts +++ b/packages/bridge/src/adapters/_client/mastodon/notifications.ts @@ -59,7 +59,7 @@ export class MastodonNotificationsRouter implements NotificationsRoute { return { data: _data }; } - async getMentions(driver: KNOWN_SOFTWARE): Promise< + async getMentions(): Promise< LibraryResponse<{ data: MastoGroupedNotificationsResults; minId?: string | null; @@ -69,8 +69,7 @@ export class MastodonNotificationsRouter implements NotificationsRoute { const { data: _data, error } = await this.direct.getCamelCaseWithLinkPagination( '/api/v2/notifications' + - '?grouped_types[]=favourite&grouped_types[]=reblog' + - '&grouped_types[]=follow&exclude_types[]=follow' + + '?exclude_types[]=follow' + '&exclude_types[]=follow_request&exclude_types[]=favourite' + '&exclude_types[]=reblog&exclude_types[]=poll' + '&exclude_types[]=status&exclude_types[]=update' + @@ -79,9 +78,24 @@ export class MastodonNotificationsRouter implements NotificationsRoute { '&exclude_types[]=severed_relationships' + '&exclude_types[]=annual_report', ); - if (error) { - return errorBuilder(); - } + if (error) return errorBuilder(); + return { data: _data }; + } + + async getSocialUpdates(query: NotificationGetQueryDto) { + const { data: _data, error } = + await this.direct.getCamelCaseWithLinkPagination( + '/api/v2/notifications' + + '?grouped_types[]=favourite&grouped_types[]=reblog' + + '&grouped_types[]=follow&exclude_types[]=follow_request' + + '&exclude_types[]=poll' + + '&exclude_types[]=status&exclude_types[]=update' + + '&exclude_types[]=admin.sign_up&exclude_types[]=admin.report' + + '&exclude_types[]=moderation_warning' + + '&exclude_types[]=severed_relationships' + + '&exclude_types[]=annual_report&exclude_types[]=mention', + ); + if (error) return errorBuilder(); return { data: _data }; } diff --git a/packages/bridge/src/adapters/_client/misskey/notifications.ts b/packages/bridge/src/adapters/_client/misskey/notifications.ts index 48b087b2..1810b54b 100644 --- a/packages/bridge/src/adapters/_client/misskey/notifications.ts +++ b/packages/bridge/src/adapters/_client/misskey/notifications.ts @@ -65,4 +65,12 @@ export class MisskeyNotificationsRouter implements NotificationsRoute { }); return { data: { data: data as any } }; } + + async getSocialUpdates(query: NotificationGetQueryDto) { + const data = await this.client.client.request< + 'i/notifications-grouped', + Endpoints['i/notifications-grouped']['req'] + >('i/notifications-grouped', query as any); + return { data: { data: data as any } }; + } } diff --git a/packages/bridge/src/adapters/_client/pleroma/notifications.ts b/packages/bridge/src/adapters/_client/pleroma/notifications.ts index f527b2a1..672889dc 100644 --- a/packages/bridge/src/adapters/_client/pleroma/notifications.ts +++ b/packages/bridge/src/adapters/_client/pleroma/notifications.ts @@ -74,4 +74,8 @@ export class PleromaNotificationsRouter implements NotificationsRoute { async getMentions() { return notImplementedErrorBuilder(); } + + async getSocialUpdates() { + return notImplementedErrorBuilder(); + } } diff --git a/yarn.lock b/yarn.lock index b987b8b9..62cebdfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,6 +1239,18 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@huggingface/inference@^2.8.1": + version "2.8.1" + resolved "https://registry.yarnpkg.com/@huggingface/inference/-/inference-2.8.1.tgz#e119a7746faf5ce40ebf37ec97afd51286c27ecb" + integrity sha512-EfsNtY9OR6JCNaUa5bZu2mrs48iqeTz0Gutwf+fU0Kypx33xFQB4DKMhp8u4Ee6qVbLbNWvTHuWwlppLQl4p4Q== + dependencies: + "@huggingface/tasks" "^0.12.9" + +"@huggingface/tasks@^0.12.9": + version "0.12.30" + resolved "https://registry.yarnpkg.com/@huggingface/tasks/-/tasks-0.12.30.tgz#ed1295c12cd85fc1ff4621485703be92083148b0" + integrity sha512-A1ITdxbEzx9L8wKR8pF7swyrTLxWNDFIGDLUWInxvks2ruQ8PLRBZe8r0EcjC3CDdtlj9jV1V4cgV35K/iy3GQ== + "@ide/backoff@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@ide/backoff/-/backoff-1.0.0.tgz#466842c25bd4a4833e0642fab41ccff064010176" @@ -2055,14 +2067,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/node-fetch@^2.6.4": - version "2.6.12" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" - integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== - dependencies: - "@types/node" "*" - form-data "^4.0.0" - "@types/node-forge@^1.3.0": version "1.3.11" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" @@ -2077,13 +2081,6 @@ dependencies: undici-types "~6.20.0" -"@types/node@^18.11.18": - version "18.19.68" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.68.tgz#f4f10d9927a7eaf3568c46a6d739cc0967ccb701" - integrity sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw== - dependencies: - undici-types "~5.26.4" - "@types/node@~20.12.8": version "20.12.14" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.14.tgz#0c5cf7ef26aedfd64b0539bba9380ed1f57dcc77" @@ -2213,13 +2210,6 @@ acorn@^8.8.2: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== -agentkeepalive@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== - dependencies: - humanize-ms "^1.2.1" - aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -3709,13 +3699,13 @@ expo-constants@~17.0.0, expo-constants@~17.0.3: "@expo/config" "~10.0.4" "@expo/env" "~0.4.0" -expo-dev-client@~5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/expo-dev-client/-/expo-dev-client-5.0.7.tgz#7902cb0443224f6fbc106e88619fd4987e5f3d1c" - integrity sha512-Ui938ZTSBHqQW9W5LY8Qb8ezf03YqX2LeYoQBh+p3Oen9XAZ67qd0NiQtssJd5GvbS5C5JTtF0OQMMhJAtiIvA== +expo-dev-client@~5.0.8: + version "5.0.8" + resolved "https://registry.yarnpkg.com/expo-dev-client/-/expo-dev-client-5.0.8.tgz#abfe5b2a0983672a5333c418918dd287620c2237" + integrity sha512-b9vEIoPBYNqCegxx1D/aZdXkLABa+JA7eFn/dygiU0HnFsr0YBFx3Lj2kzMukayy5x0u9EjMps3l/fznC1EMQg== dependencies: expo-dev-launcher "5.0.21" - expo-dev-menu "6.0.14" + expo-dev-menu "6.0.15" expo-dev-menu-interface "1.9.2" expo-manifests "~0.15.0" expo-updates-interface "~1.0.0" @@ -3742,6 +3732,13 @@ expo-dev-menu@6.0.14: dependencies: expo-dev-menu-interface "1.9.2" +expo-dev-menu@6.0.15: + version "6.0.15" + resolved "https://registry.yarnpkg.com/expo-dev-menu/-/expo-dev-menu-6.0.15.tgz#1e9d9b2ad0335bfe379317b6576165179c0a0b09" + integrity sha512-GMMOSKq9Sjv6uZJt0pSHLHAi33ZHj6mdC+ostvz1A02+U86+mujcMUozYIBTzpiL4Vzj4v7D+sJB+oW6CmDxgg== + dependencies: + expo-dev-menu-interface "1.9.2" + expo-file-system@~18.0.6: version "18.0.6" resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-18.0.6.tgz#43f7718530d0e2aa1f49bca7ccb721007acabf2c" @@ -3864,11 +3861,6 @@ expo-router@~4.0.15: semver "~7.6.3" server-only "^0.0.1" -expo-sharing@~13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/expo-sharing/-/expo-sharing-13.0.0.tgz#fbc46f4afdaa265a2811fe88c2a589aae2d2de0f" - integrity sha512-b23ymicRmYn/Pjj05sl9tFZHN5cH9I1f0yiqY1Yk8Q3oCx0Aznri82DnTYA4T/J6D9vrkraX0wQ4jWVMOffmlg== - expo-splash-screen@~0.29.18: version "0.29.18" resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.29.18.tgz#96ccce3d5a03389a9061743903b0a77c22a16796" @@ -3876,10 +3868,10 @@ expo-splash-screen@~0.29.18: dependencies: "@expo/prebuild-config" "^8.0.23" -expo-sqlite@~15.0.4: - version "15.0.4" - resolved "https://registry.yarnpkg.com/expo-sqlite/-/expo-sqlite-15.0.4.tgz#ebf9f788c8ed08969b7177d4012bfce0ddbb7c0f" - integrity sha512-RIzkFmVtK71EKdeBEiKts+sVneCrb0X83fpIRsSmuPGbGnHc8tWVibx5jh9erz+m7ZJalmaQfP1jeghiXkLi7g== +expo-sqlite@~15.0.5: + version "15.0.5" + resolved "https://registry.yarnpkg.com/expo-sqlite/-/expo-sqlite-15.0.5.tgz#ab65e4fefd8d811843d17b60a963d6182c0f731c" + integrity sha512-PtkZB/w5uyPszt2oOnh9qG6Tn1nn8mDSi+KdjATQJyrWsUPHuhN/jugJ5NYD9/TcpDEZ/chttmTgkqIhjjwqeA== expo-updates-interface@~1.0.0: version "1.0.0" @@ -4094,11 +4086,6 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" -form-data-encoder@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" - integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== - form-data@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.2.tgz#83ad9ced7c03feaad97e293d6f6091011e1659c8" @@ -4117,14 +4104,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -formdata-node@^4.3.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" - integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== - dependencies: - node-domexception "1.0.0" - web-streams-polyfill "4.0.0-beta.3" - freeport-async@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/freeport-async/-/freeport-async-2.0.0.tgz#6adf2ec0c629d11abff92836acd04b399135bab4" @@ -4451,13 +4430,6 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - i18n-js@^4.4.3: version "4.5.1" resolved "https://registry.yarnpkg.com/i18n-js/-/i18n-js-4.5.1.tgz#12ea3d6333552ff75be0904ea50705f5a263d172" @@ -5617,7 +5589,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5691,11 +5663,6 @@ node-dir@^0.1.17: dependencies: minimatch "^3.0.2" -node-domexception@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -5703,7 +5670,7 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.2.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: +node-fetch@^2.2.0, node-fetch@^2.6.1, node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -5877,19 +5844,6 @@ open@^8.0.4: is-docker "^2.1.1" is-wsl "^2.2.0" -openai@^4.76.3: - version "4.77.0" - resolved "https://registry.yarnpkg.com/openai/-/openai-4.77.0.tgz#228f2d43ffa79ae9d8b5d4155e965da82e5ac330" - integrity sha512-WWacavtns/7pCUkOWvQIjyOfcdr9X+9n9Vvb0zFeKVDAqwCMDHB+iSr24SVaBAhplvSG6JrRXFpcNM9gWhOGIw== - dependencies: - "@types/node" "^18.11.18" - "@types/node-fetch" "^2.6.4" - abort-controller "^3.0.0" - agentkeepalive "^4.2.1" - form-data-encoder "1.7.2" - formdata-node "^4.3.2" - node-fetch "^2.6.7" - ora@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" @@ -7675,11 +7629,6 @@ web-encoding@1.1.5: optionalDependencies: "@zxing/text-encoding" "0.9.0" -web-streams-polyfill@4.0.0-beta.3: - version "4.0.0-beta.3" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" - integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== - web-streams-polyfill@^3.1.1, web-streams-polyfill@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"