diff options
-rw-r--r-- | .eslintrc.js | 1 | ||||
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | app.json | 8 | ||||
-rw-r--r-- | eas.json | 14 | ||||
-rw-r--r-- | package.json | 5 | ||||
-rw-r--r-- | src/App.native.tsx | 4 | ||||
-rw-r--r-- | src/lib/api/debug-appview-proxy-header.ts | 39 | ||||
-rw-r--r-- | src/lib/bg-scheduler.ts | 18 | ||||
-rw-r--r-- | src/lib/bg-scheduler.web.ts | 13 | ||||
-rw-r--r-- | src/lib/notifee.ts | 82 | ||||
-rw-r--r-- | src/lib/notifications/notifications.ts | 101 | ||||
-rw-r--r-- | src/platform/detection.ts | 1 | ||||
-rw-r--r-- | src/state/models/feeds/notifications.ts | 30 | ||||
-rw-r--r-- | src/state/models/root-store.ts | 59 | ||||
-rw-r--r-- | src/view/screens/Debug.tsx | 7 | ||||
-rw-r--r-- | src/view/screens/Settings.tsx | 2 | ||||
-rw-r--r-- | tsconfig.check.json | 2 | ||||
-rw-r--r-- | yarn.lock | 122 |
18 files changed, 253 insertions, 260 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index c5b7e861f..a6881033a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,6 +17,7 @@ module.exports = { '.husky', 'patches', '*.html', + 'bskyweb', ], overrides: [ { diff --git a/.gitignore b/.gitignore index 2fa850bf7..66658f8e4 100644 --- a/.gitignore +++ b/.gitignore @@ -96,4 +96,7 @@ ios/ # environment variables .env -.env.* \ No newline at end of file +.env.* + +# Firebase (Android) Google services +google-services.json \ No newline at end of file diff --git a/app.json b/app.json index 4ee73752a..55250fb76 100644 --- a/app.json +++ b/app.json @@ -25,11 +25,7 @@ }, "infoPlist": { "UIBackgroundModes": [ - "fetch", - "processing" - ], - "BGTaskSchedulerPermittedIdentifiers": [ - "com.transistorsoft.fetch" + "remote-notification" ], "NSCameraUsageDescription": "Used for profile pictures, posts, and other kinds of content.", "NSMicrophoneUsageDescription": "Used for posts and other kinds of content.", @@ -48,6 +44,7 @@ "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#ffffff" }, + "googleServicesFile": "./google-services.json", "package": "xyz.blueskyweb.app", "intentFilters": [ { @@ -73,7 +70,6 @@ }, "plugins": [ "expo-localization", - "react-native-background-fetch", "sentry-expo", [ "expo-build-properties", diff --git a/eas.json b/eas.json index 60c8be378..30c3cce4b 100644 --- a/eas.json +++ b/eas.json @@ -9,20 +9,28 @@ "distribution": "internal", "ios": { "simulator": true, - "resourceClass": "medium" + "resourceClass": "large" + }, + "channel": "development" + }, + "development-device": { + "developmentClient": true, + "distribution": "internal", + "ios": { + "resourceClass": "large" }, "channel": "development" }, "preview": { "distribution": "internal", "ios": { - "resourceClass": "medium" + "resourceClass": "large" }, "channel": "preview" }, "production": { "ios": { - "resourceClass": "medium" + "resourceClass": "large" }, "channel": "production" } diff --git a/package.json b/package.json index 5eb4780ab..57ad831a3 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "e2e:run": "detox test --configuration ios.sim.debug --take-screenshots all" }, "dependencies": { - "@atproto/api": "^0.6.5", + "@atproto/api": "^0.6.6", "@bam.tech/react-native-image-resizer": "^3.0.4", "@braintree/sanitize-url": "^6.0.2", "@expo/html-elements": "^0.4.2", @@ -36,7 +36,6 @@ "@gorhom/bottom-sheet": "^4.4.7", "@mattermost/react-native-paste-input": "^0.6.4", "@miblanchard/react-native-slider": "^2.2.0", - "@notifee/react-native": "^7.4.0", "@react-native-async-storage/async-storage": "^1.17.6", "@react-native-camera-roll/camera-roll": "^5.2.2", "@react-native-clipboard/clipboard": "^1.10.0", @@ -83,6 +82,7 @@ "expo-image-picker": "^14.1.1", "expo-localization": "~14.1.1", "expo-media-library": "~15.2.3", + "expo-notifications": "~0.18.1", "expo-sharing": "~11.2.2", "expo-splash-screen": "~0.18.2", "expo-status-bar": "~1.4.4", @@ -114,7 +114,6 @@ "react-dom": "^18.2.0", "react-native": "0.71.8", "react-native-appstate-hook": "^1.0.6", - "react-native-background-fetch": "^4.1.8", "react-native-draggable-flatlist": "^4.0.1", "react-native-drawer-layout": "^3.2.0", "react-native-fs": "^2.20.0", diff --git a/src/App.native.tsx b/src/App.native.tsx index a02ca62c8..ad37aa099 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -12,7 +12,7 @@ import {s} from 'lib/styles' import * as view from './view/index' import {RootStoreModel, setupState, RootStoreProvider} from './state' import {Shell} from './view/shell' -import * as notifee from 'lib/notifee' +import * as notifications from 'lib/notifications/notifications' import * as analytics from 'lib/analytics/analytics' import * as Toast from './view/com/util/Toast' import {handleLink} from './Navigation' @@ -30,7 +30,7 @@ const App = observer(() => { setupState().then(store => { setRootStore(store) analytics.init(store) - notifee.init(store) + notifications.init(store) SplashScreen.hideAsync() Linking.getInitialURL().then((url: string | null) => { if (url) { diff --git a/src/lib/api/debug-appview-proxy-header.ts b/src/lib/api/debug-appview-proxy-header.ts index 39890b7c3..7571bd37f 100644 --- a/src/lib/api/debug-appview-proxy-header.ts +++ b/src/lib/api/debug-appview-proxy-header.ts @@ -8,23 +8,30 @@ * version of the app. */ -import {useState, useCallback} from 'react' +import {useState, useCallback, useEffect} from 'react' import {BskyAgent} from '@atproto/api' import {isWeb} from 'platform/detection' +import * as Storage from 'lib/storage' export function useDebugHeaderSetting(agent: BskyAgent): [boolean, () => void] { - const [enabled, setEnabled] = useState<boolean>(isEnabled()) + const [enabled, setEnabled] = useState<boolean>(false) - const toggle = useCallback(() => { - if (!isWeb || typeof window === 'undefined') { - return + useEffect(() => { + async function check() { + if (await isEnabled()) { + setEnabled(true) + } } + check() + }, []) + + const toggle = useCallback(() => { if (!enabled) { - localStorage.setItem('set-header-x-appview-proxy', 'yes') + Storage.saveString('set-header-x-appview-proxy', 'yes') agent.api.xrpc.setHeader('x-appview-proxy', 'true') setEnabled(true) } else { - localStorage.removeItem('set-header-x-appview-proxy') + Storage.remove('set-header-x-appview-proxy') agent.api.xrpc.unsetHeader('x-appview-proxy') setEnabled(false) } @@ -34,30 +41,24 @@ export function useDebugHeaderSetting(agent: BskyAgent): [boolean, () => void] { } export function setDebugHeader(agent: BskyAgent, enabled: boolean) { - if (!isWeb || typeof window === 'undefined') { - return - } if (enabled) { - localStorage.setItem('set-header-x-appview-proxy', 'yes') + Storage.saveString('set-header-x-appview-proxy', 'yes') agent.api.xrpc.setHeader('x-appview-proxy', 'true') } else { - localStorage.removeItem('set-header-x-appview-proxy') + Storage.remove('set-header-x-appview-proxy') agent.api.xrpc.unsetHeader('x-appview-proxy') } } -export function applyDebugHeader(agent: BskyAgent) { +export async function applyDebugHeader(agent: BskyAgent) { if (!isWeb) { return } - if (isEnabled()) { + if (await isEnabled()) { agent.api.xrpc.setHeader('x-appview-proxy', 'true') } } -function isEnabled() { - if (!isWeb || typeof window === 'undefined') { - return false - } - return localStorage.getItem('set-header-x-appview-proxy') === 'yes' +async function isEnabled() { + return (await Storage.loadString('set-header-x-appview-proxy')) === 'yes' } diff --git a/src/lib/bg-scheduler.ts b/src/lib/bg-scheduler.ts deleted file mode 100644 index db3f2d7fd..000000000 --- a/src/lib/bg-scheduler.ts +++ /dev/null @@ -1,18 +0,0 @@ -import BackgroundFetch, { - BackgroundFetchStatus, -} from 'react-native-background-fetch' - -export function configure( - handler: (taskId: string) => Promise<void>, - timeoutHandler: (taskId: string) => void, -): Promise<BackgroundFetchStatus> { - return BackgroundFetch.configure( - {minimumFetchInterval: 15}, - handler, - timeoutHandler, - ) -} - -export function finish(taskId: string) { - return BackgroundFetch.finish(taskId) -} diff --git a/src/lib/bg-scheduler.web.ts b/src/lib/bg-scheduler.web.ts deleted file mode 100644 index 91ec9428f..000000000 --- a/src/lib/bg-scheduler.web.ts +++ /dev/null @@ -1,13 +0,0 @@ -type BackgroundFetchStatus = 0 | 1 | 2 - -export async function configure( - _handler: (taskId: string) => Promise<void>, - _timeoutHandler: (taskId: string) => Promise<void>, -): Promise<BackgroundFetchStatus> { - // TODO - return 0 -} - -export function finish(_taskId: string) { - // TODO -} diff --git a/src/lib/notifee.ts b/src/lib/notifee.ts deleted file mode 100644 index 485d79aed..000000000 --- a/src/lib/notifee.ts +++ /dev/null @@ -1,82 +0,0 @@ -import notifee, {EventType} from '@notifee/react-native' -import {AppBskyEmbedImages, AtUri} from '@atproto/api' -import {RootStoreModel} from 'state/models/root-store' -import {NotificationsFeedItemModel} from 'state/models/feeds/notifications' -import {enforceLen} from 'lib/strings/helpers' -import {sanitizeDisplayName} from './strings/display-names' -import {resetToTab} from '../Navigation' - -export function init(store: RootStoreModel) { - store.onUnreadNotifications(count => notifee.setBadgeCount(count)) - store.onPushNotification(displayNotificationFromModel) - store.onSessionLoaded(() => { - // request notifications permission once the user has logged in - notifee.requestPermission() - }) - notifee.onForegroundEvent(async ({type}: {type: EventType}) => { - store.log.debug('Notifee foreground event', {type}) - if (type === EventType.PRESS) { - store.log.debug('User pressed a notifee, opening notifications') - resetToTab('NotificationsTab') - } - }) - notifee.onBackgroundEvent(async _e => {}) // notifee requires this but we handle it with onForegroundEvent -} - -export function displayNotification( - title: string, - body?: string, - image?: string, -) { - const opts: {title: string; body?: string; ios?: any} = {title} - if (body) { - opts.body = enforceLen(body, 70, true) - } - if (image) { - opts.ios = { - attachments: [{url: image}], - } - } - return notifee.displayNotification(opts) -} - -export function displayNotificationFromModel( - notification: NotificationsFeedItemModel, -) { - let author = sanitizeDisplayName( - notification.author.displayName || notification.author.handle, - ) - let title: string - let body: string = '' - if (notification.isLike) { - title = `${author} liked your post` - body = notification.additionalPost?.thread?.postRecord?.text || '' - } else if (notification.isRepost) { - title = `${author} reposted your post` - body = notification.additionalPost?.thread?.postRecord?.text || '' - } else if (notification.isMention) { - title = `${author} mentioned you` - body = notification.additionalPost?.thread?.postRecord?.text || '' - } else if (notification.isReply) { - title = `${author} replied to your post` - body = notification.additionalPost?.thread?.postRecord?.text || '' - } else if (notification.isFollow) { - title = 'New follower!' - body = `${author} has followed you` - } else if (notification.isCustomFeedLike) { - title = `${author} liked your custom feed` - body = `${new AtUri(notification.subjectUri).rkey}` - } else { - return - } - let image - if ( - AppBskyEmbedImages.isView( - notification.additionalPost?.thread?.post.embed, - ) && - notification.additionalPost?.thread?.post.embed.images[0]?.thumb - ) { - image = notification.additionalPost.thread.post.embed.images[0].thumb - } - return displayNotification(title, body, image) -} diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts new file mode 100644 index 000000000..b517b40bf --- /dev/null +++ b/src/lib/notifications/notifications.ts @@ -0,0 +1,101 @@ +import * as Notifications from 'expo-notifications' +import {RootStoreModel} from '../../state' +import {resetToTab} from '../../Navigation' +import {devicePlatform, isIOS} from 'platform/detection' + +// TODO prod did = did:web:api.bsky.app + +export function init(store: RootStoreModel) { + store.onUnreadNotifications(count => Notifications.setBadgeCountAsync(count)) + + store.onSessionLoaded(async () => { + // request notifications permission once the user has logged in + const perms = await Notifications.getPermissionsAsync() + if (!perms.granted) { + await Notifications.requestPermissionsAsync() + } + + // register the push token with the server + const token = await getPushToken() + if (token) { + try { + await store.agent.api.app.bsky.notification.registerPush({ + serviceDid: 'did:web:api.staging.bsky.dev', + platform: devicePlatform, + token: token.data, + appId: 'xyz.blueskyweb.app', + }) + store.log.debug('Notifications: Sent push token (init)', { + type: token.type, + token: token.data, + }) + } catch (error) { + store.log.error('Notifications: Failed to set push token', error) + } + } + + // listens for new changes to the push token + // In rare situations, a push token may be changed by the push notification service while the app is running. When a token is rolled, the old one becomes invalid and sending notifications to it will fail. A push token listener will let you handle this situation gracefully by registering the new token with your backend right away. + Notifications.addPushTokenListener(async ({data: t, type}) => { + store.log.debug('Notifications: Push token changed', {t, type}) + if (t) { + try { + await store.agent.api.app.bsky.notification.registerPush({ + serviceDid: 'did:web:api.staging.bsky.dev', + platform: devicePlatform, + token: t, + appId: 'xyz.blueskyweb.app', + }) + store.log.debug('Notifications: Sent push token (event)', { + type, + token: t, + }) + } catch (error) { + store.log.error('Notifications: Failed to set push token', error) + } + } + }) + }) + + // handle notifications that are tapped on, regardless of whether the app is in the foreground or background + Notifications.addNotificationReceivedListener(event => { + store.log.debug('Notifications: received', event) + if (event.request.trigger.type === 'push') { + let payload + if (isIOS) { + payload = event.request.trigger.payload + } else { + // TODO: handle android payload deeplink + } + if (payload) { + store.log.debug('Notifications: received payload', payload) + // TODO: deeplink notif here + } + } + }) + + const sub = Notifications.addNotificationResponseReceivedListener( + response => { + store.log.debug( + 'Notifications: response received', + response.actionIdentifier, + ) + if ( + response.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER + ) { + store.log.debug( + 'User pressed a notification, opening notifications tab', + ) + resetToTab('NotificationsTab') + } + }, + ) + + return () => { + sub.remove() + } +} + +export function getPushToken() { + return Notifications.getDevicePushTokenAsync() +} diff --git a/src/platform/detection.ts b/src/platform/detection.ts index 3069c9be2..41ca20e5d 100644 --- a/src/platform/detection.ts +++ b/src/platform/detection.ts @@ -5,6 +5,7 @@ import {dedupArray} from 'lib/functions' export const isIOS = Platform.OS === 'ios' export const isAndroid = Platform.OS === 'android' export const isNative = isIOS || isAndroid +export const devicePlatform = isIOS ? 'ios' : isAndroid ? 'android' : 'web' export const isWeb = !isNative export const isMobileWebMediaQuery = 'only screen and (max-width: 1230px)' export const isMobileWeb = diff --git a/src/state/models/feeds/notifications.ts b/src/state/models/feeds/notifications.ts index f52853070..a9836d38f 100644 --- a/src/state/models/feeds/notifications.ts +++ b/src/state/models/feeds/notifications.ts @@ -478,36 +478,6 @@ export class NotificationsFeedModel { } } - /** - * Used in background fetch to trigger notifications - */ - async getNewMostRecent(): Promise<NotificationsFeedItemModel | undefined> { - let old = this.mostRecentNotificationUri - const res = await this.rootStore.agent.listNotifications({ - limit: 1, - }) - if (!res.data.notifications[0] || old === res.data.notifications[0].uri) { - return - } - this.mostRecentNotificationUri = res.data.notifications[0].uri - const notif = new NotificationsFeedItemModel( - this.rootStore, - 'mostRecent', - res.data.notifications[0], - ) - const addedUri = notif.additionalDataUri - if (addedUri) { - const postsRes = await this.rootStore.agent.app.bsky.feed.getPosts({ - uris: [addedUri], - }) - const post = postsRes.data.posts[0] - notif.setAdditionalData(post) - this.rootStore.posts.set(post.uri, post) - } - const filtered = this._filterNotifications([notif]) - return filtered[0] - } - // state transitions // = diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts index 6ced8090a..1d6d3a0d0 100644 --- a/src/state/models/root-store.ts +++ b/src/state/models/root-store.ts @@ -6,7 +6,6 @@ import {makeAutoObservable} from 'mobx' import {BskyAgent} from '@atproto/api' import {createContext, useContext} from 'react' import {DeviceEventEmitter, EmitterSubscription} from 'react-native' -import * as BgScheduler from 'lib/bg-scheduler' import {z} from 'zod' import {isObj, hasProp} from 'lib/type-guards' import {LogModel} from './log' @@ -16,7 +15,6 @@ import {HandleResolutionsCache} from './cache/handle-resolutions' import {ProfilesCache} from './cache/profiles-view' import {PostsCache} from './cache/posts' import {LinkMetasCache} from './cache/link-metas' -import {NotificationsFeedItemModel} from './feeds/notifications' import {MeModel} from './me' import {InvitedUsers} from './invited-users' import {PreferencesModel} from './ui/preferences' @@ -61,7 +59,6 @@ export class RootStoreModel { serialize: false, hydrate: false, }) - this.initBgFetch() } setAppInfo(info: AppInfo) { @@ -249,62 +246,6 @@ export class RootStoreModel { emitUnreadNotifications(count: number) { DeviceEventEmitter.emit('unread-notifications', count) } - - // a notification has been queued for push - onPushNotification( - handler: (notif: NotificationsFeedItemModel) => void, - ): EmitterSubscription { - return DeviceEventEmitter.addListener('push-notification', handler) - } - emitPushNotification(notif: NotificationsFeedItemModel) { - DeviceEventEmitter.emit('push-notification', notif) - } - - // background fetch - // = - // - we use this to poll for unread notifications, which is not "ideal" behavior but - // gives us a solution for push-notifications that work against any pds - - initBgFetch() { - // NOTE - // background fetch runs every 15 minutes *at most* and will get slowed down - // based on some heuristics run by iOS, meaning it is not a reliable form of delivery - // -prf - BgScheduler.configure( - this.onBgFetch.bind(this), - this.onBgFetchTimeout.bind(this), - ).then(status => { - this.log.debug(`Background fetch initiated, status: ${status}`) - }) - } - - async onBgFetch(taskId: string) { - this.log.debug(`Background fetch fired for task ${taskId}`) - if (this.session.hasSession) { - const res = await this.agent.countUnreadNotifications() - const hasNewNotifs = this.me.notifications.unreadCount !== res.data.count - this.emitUnreadNotifications(res.data.count) - this.log.debug( - `Background fetch received unread count = ${res.data.count}`, - ) - if (hasNewNotifs) { - this.log.debug( - 'Background fetch detected potentially a new notification', - ) - const mostRecent = await this.me.notifications.getNewMostRecent() - if (mostRecent) { - this.log.debug('Got the notification, triggering a push') - this.emitPushNotification(mostRecent) - } - } - } - BgScheduler.finish(taskId) - } - - onBgFetchTimeout(taskId: string) { - this.log.debug(`Background fetch timed out for task ${taskId}`) - BgScheduler.finish(taskId) - } } const throwawayInst = new RootStoreModel( diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx index 852025324..0e0464200 100644 --- a/src/view/screens/Debug.tsx +++ b/src/view/screens/Debug.tsx @@ -5,9 +5,7 @@ import {ViewHeader} from '../com/util/ViewHeader' import {ThemeProvider, PaletteColorName} from 'lib/ThemeContext' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' -import {displayNotification} from 'lib/notifee' import * as Toast from 'view/com/util/Toast' - import {Text} from '../com/util/text/Text' import {ViewSelector} from '../com/util/ViewSelector' import {EmptyState} from '../com/util/EmptyState' @@ -177,10 +175,7 @@ function ErrorView() { function NotifsView() { const triggerPush = () => { - displayNotification( - 'Paul Frazee liked your post', - "Hello world! This is a test of the notifications card. The text is long to see how that's handled.", - ) + // TODO: implement local notification for testing } const triggerToast = () => { Toast.show('The task has been completed') diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index 478fcaa09..f1d4767f3 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -505,7 +505,7 @@ export const SettingsScreen = withAuthRequired( System log </Text> </TouchableOpacity> - {isDesktopWeb ? ( + {isDesktopWeb || __DEV__ ? ( <ToggleButton type="default-light" label="Experiment: Use AppView Proxy" diff --git a/tsconfig.check.json b/tsconfig.check.json index f2e29bbb7..b90fc83e0 100644 --- a/tsconfig.check.json +++ b/tsconfig.check.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": ["__e2e__", "dist"], + "include": ["src"] } diff --git a/yarn.lock b/yarn.lock index 1a9fed10b..e53c4626a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,10 +40,10 @@ tlds "^1.234.0" typed-emitter "^2.1.0" -"@atproto/api@^0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.6.5.tgz#496a011b7e8fbf2af32a30cec07a021aa6ef3f4b" - integrity sha512-u6NVkYpdUU5jKGxio2FIRmok0LL+eqqMzihm9LDfydZ4Pi4NqfrOrWw0H1WA7zO3vH9AaxnLSMTwSEAkRRb2FA== +"@atproto/api@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.6.6.tgz#c1bfdb6bc7dee9cdba1901cde0081c2d422d7c29" + integrity sha512-j+yNTjllVxuTc4bAegghTopju7MdhczLXWvWIli40uXwCzQ3JjS1mFr/47eETtysib2phWYQvfhtCrqQq6AAig== dependencies: "@atproto/common-web" "*" "@atproto/uri" "*" @@ -3089,7 +3089,7 @@ semver "7.3.2" tempy "0.3.0" -"@expo/image-utils@0.3.23": +"@expo/image-utils@0.3.23", "@expo/image-utils@^0.3.18": version "0.3.23" resolved "https://registry.yarnpkg.com/@expo/image-utils/-/image-utils-0.3.23.tgz#f14fd7e1f5ff6f8e4911a41e27dd274470665c3f" integrity sha512-nhUVvW0TrRE4jtWzHQl8TR4ox7kcmrc2I0itaeJGjxF5A54uk7avgA0wRt7jP1rdvqQo1Ke1lXyLYREdhN9tPw== @@ -3362,6 +3362,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@ide/backoff@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@ide/backoff/-/backoff-1.0.0.tgz#466842c25bd4a4833e0642fab41ccff064010176" + integrity sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g== + "@ipld/car@^3.2.3": version "3.2.4" resolved "https://registry.yarnpkg.com/@ipld/car/-/car-3.2.4.tgz#115951ba2255ec51d865773a074e422c169fb01c" @@ -3982,11 +3987,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@notifee/react-native@^7.4.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@notifee/react-native/-/react-native-7.8.0.tgz#2990883753990f3585aa0cb5becc5cbdbcd87a43" - integrity sha512-sx8h62U4FrR4pqlbN1rkgPsdamDt9Tad0zgfO6VtP6rNJq/78k8nxUnh0xIX3WPDcCV8KAzdYCE7+UNvhF1CpQ== - "@npmcli/fs@^1.0.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" @@ -7290,6 +7290,16 @@ asn1.js@^5.0.1: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -7664,6 +7674,11 @@ babel-preset-react-app@^10.0.1: babel-plugin-macros "^3.1.0" babel-plugin-transform-react-remove-prop-types "^0.4.24" +badgin@^1.1.5: + version "1.2.3" + resolved "https://registry.yarnpkg.com/badgin/-/badgin-1.2.3.tgz#994b5f519827d7d5422224825b2c8faea2bc43ad" + integrity sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -9772,6 +9787,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw== + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -10252,7 +10272,7 @@ expect@^29.0.0, expect@^29.5.0: jest-message-util "^29.5.0" jest-util "^29.5.0" -expo-application@~5.1.1: +expo-application@~5.1.0, expo-application@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/expo-application/-/expo-application-5.1.1.tgz#5206bf0cf89cb0e32d1f5037a0481e5c86b951ab" integrity sha512-aDatTcTTCdTbHw8h4/Tq2ilc6InM5ntF9xWCJdOcnUEcglxxGphVI/lzJKBaBF6mJECA8mEOjpVg2EGxOctTwg== @@ -10425,6 +10445,21 @@ expo-modules-core@1.2.7: compare-versions "^3.4.0" invariant "^2.2.4" +expo-notifications@~0.18.1: + version "0.18.1" + resolved "https://registry.yarnpkg.com/expo-notifications/-/expo-notifications-0.18.1.tgz#c726bee7b6691d5f154b874afeda3b4561571cfc" + integrity sha512-lOEiuPE6ubkS5u7Nj/57gkmUGD/MxsRTC6bg9SGJqXIitBQZk3Tmv9y8bjTrn71n7DsrH8K7xCZTbVwr+kLQGg== + dependencies: + "@expo/image-utils" "^0.3.18" + "@ide/backoff" "^1.0.0" + abort-controller "^3.0.0" + assert "^2.0.0" + badgin "^1.1.5" + expo-application "~5.1.0" + expo-constants "~14.2.0" + fs-extra "^9.1.0" + uuid "^3.4.0" + expo-pwa@0.0.125: version "0.0.125" resolved "https://registry.yarnpkg.com/expo-pwa/-/expo-pwa-0.0.125.tgz#fb5a66f21e7c9a51cdfa76d692b48bd116e6e002" @@ -11951,6 +11986,14 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" @@ -12121,6 +12164,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -12152,6 +12202,14 @@ is-module@^1.0.0: resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -12292,6 +12350,13 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" +is-typed-array@^1.1.3: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -15149,6 +15214,14 @@ object-inspect@^1.12.3, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -16985,11 +17058,6 @@ react-native-appstate-hook@^1.0.6: resolved "https://registry.yarnpkg.com/react-native-appstate-hook/-/react-native-appstate-hook-1.0.6.tgz#cbc16e7b89cfaea034cabd999f00e99053cabd06" integrity sha512-0hPVyf5yLxCSVrrNEuGqN1ZnSSj3Ye2gZex0NtcK/AHYwMc0rXWFNZjBKOoZSouspqu3hXBbQ6NOUSTzrME1AQ== -react-native-background-fetch@^4.1.8: - version "4.1.10" - resolved "https://registry.yarnpkg.com/react-native-background-fetch/-/react-native-background-fetch-4.1.10.tgz#12c7e85140af67fb05edb7cd9960e4f09a457797" - integrity sha512-Ug54vTctZuD/c06ZLk/VyvFdhw/hCVVOHYR5heyMqc6FlT/m9fVhFWyl4uH3JmPCzmWDVR3fO28CzrGpKOrusw== - react-native-codegen@^0.71.5: version "0.71.5" resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.71.5.tgz#454a42a891cd4ca5fc436440d301044dc1349c14" @@ -19704,6 +19772,17 @@ util.promisify@~1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.0" +util@^0.12.0: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" @@ -20104,6 +20183,17 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== +which-typed-array@^1.1.11, which-typed-array@^1.1.2: + version "1.1.11" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which-typed-array@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" |