diff --git a/app.config.ts b/app.config.ts index c88cff5..2f3a862 100644 --- a/app.config.ts +++ b/app.config.ts @@ -44,7 +44,6 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ supportsTablet: true, bundleIdentifier: Env.BUNDLE_ID, requireFullScreen: true, - googleServicesFile: 'GoogleService-Info.plist', infoPlist: { UIBackgroundModes: ['remote-notification', 'audio', 'bluetooth-central', 'voip'], ITSAppUsesNonExemptEncryption: false, @@ -54,6 +53,10 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ LSApplicationQueriesSchemes: ['resgridunit'], }, entitlements: { + // Required for APNs registration. Previously added by the expo-notifications + // plugin; set explicitly so removing/swapping plugins can never silently drop + // it (which previously broke ALL iOS push — see docs/ios-foreground-notifications-fix.md). + 'aps-environment': 'production', ...((Env.APP_ENV === 'production' || Env.APP_ENV === 'internal') && { 'com.apple.developer.usernotifications.critical-alerts': true, 'com.apple.developer.usernotifications.time-sensitive': true, @@ -169,13 +172,6 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ }, ios: { deploymentTarget: '18.1', - useFrameworks: 'static', - // Build React Native from source instead of the prebuilt - // ReactNativeDependencies.xcframework. The prebuilt core does not - // re-export RN's preprocessor macros (RCT_EXTERN, RCT_CONCAT) across - // the static-framework module boundary, so RCT_EXPORT_MODULE() fails - // to compile in third-party Obj-C modules like @react-native-firebase. - buildReactNativeFromSource: true, }, }, ], @@ -223,12 +219,10 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ 'react-native-ble-manager', '@livekit/react-native-expo-plugin', '@config-plugins/react-native-webrtc', - './plugins/withWebRTCFrameworkFix.js', '@config-plugins/react-native-callkeep', - '@react-native-firebase/app', + 'expo-notifications', './customGradle.plugin.js', './customManifest.plugin.js', - './plugins/withForegroundNotifications.js', './plugins/withNotificationSounds.js', './plugins/withMediaButtonModule.js', [ diff --git a/metro.config.js b/metro.config.js index 3eaa5b8..50429da 100644 --- a/metro.config.js +++ b/metro.config.js @@ -27,8 +27,6 @@ config.resolver.resolveRequest = (context, moduleName, platform) => { // Native modules that need web shims const nativeModules = [ '@notifee/react-native', - '@react-native-firebase/messaging', - '@react-native-firebase/app', 'react-native-callkeep', 'react-native-ble-manager', '@livekit/react-native', diff --git a/package.json b/package.json index 12b91aa..ad6b27e 100644 --- a/package.json +++ b/package.json @@ -98,8 +98,6 @@ "@notifee/react-native": "9.1.8", "@novu/react-native": "3.11.0", "@react-native-community/netinfo": "11.4.1", - "@react-native-firebase/app": "23.5.0", - "@react-native-firebase/messaging": "23.5.0", "@rnmapbox/maps": "10.2.10", "@semantic-release/git": "10.0.1", "@sentry/react-native": "8.10.0", @@ -135,6 +133,7 @@ "expo-localization": "17.0.8", "expo-location": "19.0.8", "expo-navigation-bar": "5.0.10", + "expo-notifications": "0.32.16", "expo-router": "6.0.23", "expo-screen-orientation": "9.0.8", "expo-secure-store": "15.0.8", diff --git a/src/services/__tests__/push-notification.test.ts b/src/services/__tests__/push-notification.test.ts index 2372baa..a3c22b8 100644 --- a/src/services/__tests__/push-notification.test.ts +++ b/src/services/__tests__/push-notification.test.ts @@ -1,6 +1,3 @@ -import messaging from '@react-native-firebase/messaging'; -import notifee from '@notifee/react-native'; - import { usePushNotificationModalStore } from '@/stores/push-notification/store'; // Mock the store @@ -75,53 +72,47 @@ jest.mock('@/stores/app/location-store', () => ({ }, })); -// Mock Firebase messaging -const mockFcmUnsubscribe = jest.fn(); -const mockOnMessage = jest.fn(() => mockFcmUnsubscribe); -const mockOnNotificationOpenedApp = jest.fn(() => mockFcmUnsubscribe); -const mockGetInitialNotification = jest.fn(() => Promise.resolve(null)); -const mockSetBackgroundMessageHandler = jest.fn(); -const mockGetToken = jest.fn(() => Promise.resolve('test-fcm-token')); -const mockHasPermission = jest.fn(() => Promise.resolve(1)); // AUTHORIZED -const mockFcmRequestPermission = jest.fn(() => Promise.resolve(1)); // AUTHORIZED - -jest.mock('@react-native-firebase/messaging', () => { - const messagingInstance = { - onMessage: mockOnMessage, - onNotificationOpenedApp: mockOnNotificationOpenedApp, - getInitialNotification: mockGetInitialNotification, - setBackgroundMessageHandler: mockSetBackgroundMessageHandler, - getToken: mockGetToken, - hasPermission: mockHasPermission, - requestPermission: mockFcmRequestPermission, - }; - - const messagingModule = jest.fn(() => messagingInstance); - (messagingModule as any).AuthorizationStatus = { - NOT_DETERMINED: 0, - DENIED: 2, - AUTHORIZED: 1, - PROVISIONAL: 3, - }; - - return messagingModule; -}); +// Mock expo-notifications (the push transport) +const mockReceivedRemove = jest.fn(); +const mockResponseRemove = jest.fn(); +const mockSetNotificationHandler = jest.fn(); +const mockAddNotificationReceivedListener = jest.fn(() => ({ remove: mockReceivedRemove })); +const mockAddNotificationResponseReceivedListener = jest.fn(() => ({ remove: mockResponseRemove })); +const mockGetLastNotificationResponseAsync = jest.fn(() => Promise.resolve(null)); +const mockGetPermissionsAsync = jest.fn(() => Promise.resolve({ status: 'granted' })); +const mockRequestPermissionsAsync = jest.fn(() => Promise.resolve({ status: 'granted' })); +const mockGetDevicePushTokenAsync = jest.fn(() => Promise.resolve({ data: 'test-device-token' })); + +jest.mock('expo-notifications', () => ({ + setNotificationHandler: mockSetNotificationHandler, + addNotificationReceivedListener: mockAddNotificationReceivedListener, + addNotificationResponseReceivedListener: mockAddNotificationResponseReceivedListener, + getLastNotificationResponseAsync: mockGetLastNotificationResponseAsync, + getPermissionsAsync: mockGetPermissionsAsync, + requestPermissionsAsync: mockRequestPermissionsAsync, + getDevicePushTokenAsync: mockGetDevicePushTokenAsync, + AndroidImportance: { MAX: 5, HIGH: 4, DEFAULT: 3 }, + AndroidNotificationVisibility: { PUBLIC: 1 }, +})); -// Mock Notifee +// Mock Notifee (channels, categories, foreground/background events, check-in) +const mockNotifeeForegroundUnsubscribe = jest.fn(); const mockCreateChannel = jest.fn(() => Promise.resolve()); +const mockSetNotificationCategories = jest.fn(() => Promise.resolve()); const mockNotifeeRequestPermission = jest.fn(() => Promise.resolve({ authorizationStatus: 1, // AUTHORIZED }) ); const mockDisplayNotification = jest.fn(() => Promise.resolve('notification-id')); -const mockOnForegroundEvent = jest.fn(() => jest.fn()); +const mockOnForegroundEvent = jest.fn(() => mockNotifeeForegroundUnsubscribe); const mockOnBackgroundEvent = jest.fn(); jest.mock('@notifee/react-native', () => ({ __esModule: true, default: { createChannel: mockCreateChannel, + setNotificationCategories: mockSetNotificationCategories, requestPermission: mockNotifeeRequestPermission, displayNotification: mockDisplayNotification, onForegroundEvent: mockOnForegroundEvent, @@ -138,6 +129,10 @@ jest.mock('@notifee/react-native', () => ({ AUTHORIZED: 1, DENIED: 2, }, + EventType: { + PRESS: 1, + ACTION_PRESS: 2, + }, })); describe('Push Notification Service Integration', () => { @@ -158,41 +153,48 @@ describe('Push Notification Service Integration', () => { }); }); - const createMockRemoteMessage = (data: any): any => ({ - messageId: 'test-message-id', - data: data.data || {}, - notification: { - title: data.title || null, - body: data.body || null, + // Builds an expo-notifications Notification shape with the given data/title/body. + const createMockNotification = (data: any): any => ({ + request: { + content: { + title: data.title ?? null, + body: data.body ?? null, + data: data.data ?? {}, + }, }, - sentTime: Date.now(), }); - // Test the notification handling logic directly - const simulateNotificationReceived = (remoteMessage: any): void => { - const data = remoteMessage.data; + // Mirrors the service's eventCode → modal contract for the received handler. + const simulateNotificationReceived = (notification: any): void => { + const content = notification.request.content; + const data = content.data; - // Check if the notification has an eventCode and show modal // eventCode must be a string to be valid if (data && data.eventCode && typeof data.eventCode === 'string') { - const notificationData = { + const notificationData: any = { eventCode: data.eventCode as string, - title: remoteMessage.notification?.title || undefined, - body: remoteMessage.notification?.body || undefined, data, }; - - // Show the notification modal using the store - usePushNotificationModalStore.getState().showNotificationModal(notificationData).catch((err) => { - // Handle error in test environment - console.error('Error showing notification modal:', err); - }); + if (content.title) { + notificationData.title = content.title; + } + if (content.body) { + notificationData.body = content.body; + } + + usePushNotificationModalStore + .getState() + .showNotificationModal(notificationData) + .catch((err: unknown) => { + // Handle error in test environment + console.error('Error showing notification modal:', err); + }); } }; describe('notification received handler', () => { it('should show modal for call notification with eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Emergency Call', body: 'Structure fire at Main St', data: { @@ -201,7 +203,7 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'C:1234', @@ -215,7 +217,7 @@ describe('Push Notification Service Integration', () => { }); it('should show modal for message notification with eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'New Message', body: 'You have a new message from dispatch', data: { @@ -224,7 +226,7 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'M:5678', @@ -238,7 +240,7 @@ describe('Push Notification Service Integration', () => { }); it('should show modal for chat notification with eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Chat Message', body: 'New message in chat', data: { @@ -247,7 +249,7 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'T:9101', @@ -261,7 +263,7 @@ describe('Push Notification Service Integration', () => { }); it('should show modal for group chat notification with eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Group Chat', body: 'New message in group chat', data: { @@ -270,7 +272,7 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'G:1121', @@ -284,7 +286,7 @@ describe('Push Notification Service Integration', () => { }); it('should not show modal for notification without eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Regular Notification', body: 'This is a regular notification without eventCode', data: { @@ -292,13 +294,13 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).not.toHaveBeenCalled(); }); it('should not show modal for notification with empty eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Empty Event Code', body: 'This notification has empty eventCode', data: { @@ -306,37 +308,36 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).not.toHaveBeenCalled(); }); it('should not show modal for notification without data', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'No Data', body: 'This notification has no data object', data: null, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).not.toHaveBeenCalled(); }); it('should handle notification with only title', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Emergency Call', data: { eventCode: 'C:1234', }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'C:1234', title: 'Emergency Call', - body: undefined, data: { eventCode: 'C:1234', }, @@ -344,18 +345,17 @@ describe('Push Notification Service Integration', () => { }); it('should handle notification with only body', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ body: 'Structure fire at Main St', data: { eventCode: 'C:1234', }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'C:1234', - title: undefined, body: 'Structure fire at Main St', data: { eventCode: 'C:1234', @@ -364,7 +364,7 @@ describe('Push Notification Service Integration', () => { }); it('should handle notification with additional data fields', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Emergency Call', body: 'Structure fire at Main St', data: { @@ -379,7 +379,7 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).toHaveBeenCalledWith({ eventCode: 'C:1234', @@ -399,7 +399,7 @@ describe('Push Notification Service Integration', () => { }); it('should not show modal for notification with non-string eventCode', () => { - const remoteMessage = createMockRemoteMessage({ + const notification = createMockNotification({ title: 'Non-string Event Code', body: 'This notification has non-string eventCode', data: { @@ -407,38 +407,13 @@ describe('Push Notification Service Integration', () => { }, }); - simulateNotificationReceived(remoteMessage); + simulateNotificationReceived(notification); expect(mockShowNotificationModal).not.toHaveBeenCalled(); }); }); - describe('iOS foreground notification display', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should display notification on iOS when app is in foreground with emergency priority', () => { - const remoteMessage = createMockRemoteMessage({ - title: 'Emergency Call', - body: 'Structure fire at Main St', - data: { - eventCode: 'C:1234', - priority: '0', - }, - }); - - // Since the service is already instantiated with iOS platform mock, - // we just need to verify the notification would be displayed - // The actual iOS-specific test needs to run on iOS platform - // For now, verify that the notification data structure is correct - expect(remoteMessage.notification).toBeDefined(); - expect(remoteMessage.notification.title).toBe('Emergency Call'); - expect(remoteMessage.data.priority).toBe('0'); - }); - }); - - describe('listener cleanup', () => { + describe('listener lifecycle', () => { let pushNotificationService: any; beforeEach(() => { @@ -451,19 +426,17 @@ describe('Push Notification Service Integration', () => { pushNotificationService = module.pushNotificationService; }); - it('should store listener handles on initialization', async () => { + it('should register expo-notifications listeners on initialization', async () => { jest.useFakeTimers(); - + await pushNotificationService.initialize(); - // Run all timers to trigger getInitialNotification which is called in setTimeout + // Run timers to trigger the killed-state getLastNotificationResponseAsync() jest.runAllTimers(); - // Verify listeners were registered - expect(mockOnMessage).toHaveBeenCalled(); - expect(mockOnNotificationOpenedApp).toHaveBeenCalled(); - expect(mockGetInitialNotification).toHaveBeenCalled(); - expect(mockSetBackgroundMessageHandler).toHaveBeenCalled(); + expect(mockAddNotificationReceivedListener).toHaveBeenCalled(); + expect(mockAddNotificationResponseReceivedListener).toHaveBeenCalled(); + expect(mockGetLastNotificationResponseAsync).toHaveBeenCalled(); jest.useRealTimers(); }); @@ -471,26 +444,24 @@ describe('Push Notification Service Integration', () => { it('should properly cleanup all listeners', async () => { await pushNotificationService.initialize(); - // Clear previous calls - mockFcmUnsubscribe.mockClear(); + mockReceivedRemove.mockClear(); + mockResponseRemove.mockClear(); + mockNotifeeForegroundUnsubscribe.mockClear(); - // Call cleanup pushNotificationService.cleanup(); - // Verify all listeners were removed - // FCM unsubscribe should be called twice (onMessage and onNotificationOpenedApp) - expect(mockFcmUnsubscribe).toHaveBeenCalledTimes(2); + expect(mockReceivedRemove).toHaveBeenCalledTimes(1); + expect(mockResponseRemove).toHaveBeenCalledTimes(1); + expect(mockNotifeeForegroundUnsubscribe).toHaveBeenCalledTimes(1); }); it('should not error when cleanup is called without initialization', () => { - // Should not throw when cleanup is called without initializing expect(() => pushNotificationService.cleanup()).not.toThrow(); }); it('should not error when cleanup is called multiple times', async () => { await pushNotificationService.initialize(); - // Should not throw when cleanup is called multiple times expect(() => { pushNotificationService.cleanup(); pushNotificationService.cleanup(); @@ -513,37 +484,44 @@ describe('Push Notification Service Integration', () => { }); it('should successfully register for push notifications with iOS', async () => { - mockHasPermission.mockResolvedValueOnce(1); // AUTHORIZED - mockGetToken.mockResolvedValueOnce('test-fcm-token'); + mockGetPermissionsAsync.mockResolvedValueOnce({ status: 'granted' }); + mockGetDevicePushTokenAsync.mockResolvedValueOnce({ data: 'test-device-token' }); const token = await pushNotificationService.registerForPushNotifications('unit-123', 'TEST'); - expect(token).toBe('test-fcm-token'); - expect(mockHasPermission).toHaveBeenCalled(); - expect(mockGetToken).toHaveBeenCalled(); + expect(token).toBe('test-device-token'); + expect(mockGetPermissionsAsync).toHaveBeenCalled(); + expect(mockGetDevicePushTokenAsync).toHaveBeenCalled(); }); - it('should request permission if not determined', async () => { - mockHasPermission.mockResolvedValueOnce(0); // NOT_DETERMINED - mockFcmRequestPermission.mockResolvedValueOnce(1); // AUTHORIZED - mockGetToken.mockResolvedValueOnce('test-fcm-token'); + it('should request permission if not already granted', async () => { + mockGetPermissionsAsync.mockResolvedValueOnce({ status: 'undetermined' }); + mockRequestPermissionsAsync.mockResolvedValueOnce({ status: 'granted' }); + mockGetDevicePushTokenAsync.mockResolvedValueOnce({ data: 'test-device-token' }); const token = await pushNotificationService.registerForPushNotifications('unit-123', 'TEST'); - expect(token).toBe('test-fcm-token'); - expect(mockHasPermission).toHaveBeenCalled(); - expect(mockFcmRequestPermission).toHaveBeenCalled(); - expect(mockGetToken).toHaveBeenCalled(); + expect(token).toBe('test-device-token'); + expect(mockGetPermissionsAsync).toHaveBeenCalled(); + expect(mockRequestPermissionsAsync).toHaveBeenCalled(); + expect(mockGetDevicePushTokenAsync).toHaveBeenCalled(); }); it('should return null if permission is denied', async () => { - mockHasPermission.mockResolvedValueOnce(2); // DENIED - mockFcmRequestPermission.mockResolvedValueOnce(2); // DENIED + mockGetPermissionsAsync.mockResolvedValueOnce({ status: 'undetermined' }); + mockRequestPermissionsAsync.mockResolvedValueOnce({ status: 'denied' }); const token = await pushNotificationService.registerForPushNotifications('unit-123', 'TEST'); expect(token).toBeNull(); - expect(mockGetToken).not.toHaveBeenCalled(); + expect(mockGetDevicePushTokenAsync).not.toHaveBeenCalled(); + }); + + it('should return null when called without an active unit ID', async () => { + const token = await pushNotificationService.registerForPushNotifications('', 'TEST'); + + expect(token).toBeNull(); + expect(mockGetDevicePushTokenAsync).not.toHaveBeenCalled(); }); }); @@ -571,7 +549,6 @@ describe('Push Notification Service Integration', () => { it('should create notification channels on Android', async () => { await pushNotificationService.initialize(); - // Verify channels were created // Standard channels: calls, 0-3, notif, message = 7 // Custom channels: c1-c25 = 25 // Total: 32 channels diff --git a/src/services/push-notification.ts b/src/services/push-notification.ts index 9362179..6ff0034 100644 --- a/src/services/push-notification.ts +++ b/src/services/push-notification.ts @@ -1,6 +1,6 @@ import notifee, { AndroidImportance, AndroidVisibility, AuthorizationStatus, EventType } from '@notifee/react-native'; -import messaging, { type FirebaseMessagingTypes } from '@react-native-firebase/messaging'; import * as Device from 'expo-device'; +import * as Notifications from 'expo-notifications'; import { useEffect, useRef } from 'react'; import { Platform } from 'react-native'; @@ -18,6 +18,12 @@ import { securityStore } from '@/stores/security/store'; const CHECK_IN_TYPE_PERSONNEL = 0; const CHECK_IN_TYPE_UNIT = 1; +// Delays (ms) before showing the modal on a notification tap, so the React tree +// is mounted and the store is ready. See docs/ios-push-notification-tap-fix.md. +const TAP_BACKGROUND_DELAY_MS = 300; +const TAP_KILLED_INITIAL_DELAY_MS = 1000; +const TAP_KILLED_MODAL_DELAY_MS = 500; + // Define notification response types export interface PushNotificationData { title?: string; @@ -25,12 +31,25 @@ export interface PushNotificationData { data?: Record; } +// Configure how notifications are presented while the app is in the foreground. +// With expo-notifications owning the UNUserNotificationCenter delegate (Firebase +// no longer does), this controls the native banner/sound/badge presentation. +Notifications.setNotificationHandler({ + handleNotification: async () => ({ + shouldShowAlert: true, + shouldPlaySound: true, + shouldSetBadge: true, + shouldShowBanner: true, + shouldShowList: true, + }), +}); + class PushNotificationService { private static instance: PushNotificationService; private pushToken: string | null = null; - private fcmOnMessageUnsubscribe: (() => void) | null = null; - private fcmOnNotificationOpenedAppUnsubscribe: (() => void) | null = null; - private backgroundMessageHandlerRegistered: boolean = false; + private notificationListener: { remove: () => void } | null = null; + private responseListener: { remove: () => void } | null = null; + private notifeeForegroundUnsubscribe: (() => void) | null = null; public static getInstance(): PushNotificationService { if (!PushNotificationService.instance) { @@ -116,80 +135,59 @@ class PushNotificationService { } } - private handleRemoteMessage = async (remoteMessage: any): Promise => { - logger.info({ - message: 'FCM message received', - context: { - data: remoteMessage.data, - notification: remoteMessage.notification, - }, - }); + // Shared helper: show the in-app modal when a notification carries an eventCode. + private showModalForData(data: Record | undefined, title?: string | null, body?: string | null): void { + const eventCode = data?.eventCode; + if (!eventCode || typeof eventCode !== 'string') { + return; + } - // Extract eventCode and other data based on platform - // For Android: data.eventCode, data.type, data.title, data.message - // For iOS: comes through notification or data - const eventCode = remoteMessage.data?.eventCode as string | undefined; - const customType = remoteMessage.data?.type || remoteMessage.data?.customType; - const title = (remoteMessage.data?.title as string) || remoteMessage.notification?.title; - const body = (remoteMessage.data?.message as string) || remoteMessage.notification?.body; - const category = remoteMessage.data?.category || remoteMessage.notification?.android?.channelId; - - // On iOS, display the notification in foreground using Notifee - if (Platform.OS === 'ios' && remoteMessage.notification) { - try { - // Determine if this is a critical alert (calls) - const isCritical = category === 'calls' || customType === '0'; + const notificationData: PushNotificationData & { eventCode: string } = { + eventCode, + data, + }; + if (title) { + notificationData.title = title; + } + if (body) { + notificationData.body = body; + } - // Extract sound name from FCM payload, fallback to 'default' - const sound = (remoteMessage.data?.sound as string) || 'default'; + void usePushNotificationModalStore.getState().showNotificationModal(notificationData); + } - await notifee.displayNotification({ - title: title, - body: body, - ios: { - sound: sound, - criticalVolume: 1.0, - critical: isCritical, - categoryId: (category as string) || 'calls', - }, - data: remoteMessage.data as Record, - }); - } catch (error) { - logger.error({ - message: 'Error displaying iOS foreground notification', - context: { error }, - }); - } - } + // Foreground push received via expo-notifications. + private handleNotificationReceived = (notification: Notifications.Notification): void => { + const data = notification.request.content.data as Record | undefined; - // Check if the notification has an eventCode and show modal - // eventCode must be a string to be valid - if (eventCode && typeof eventCode === 'string') { - const notificationData = { - eventCode: eventCode, - title: title, - body: body, - data: remoteMessage.data, - }; - - // Show the notification modal using the store - await usePushNotificationModalStore.getState().showNotificationModal(notificationData); - } + logger.info({ + message: 'Notification received', + context: { data }, + }); + + this.showModalForData(data, notification.request.content.title, notification.request.content.body); }; - async initialize(): Promise { - // Push notifications are native-only; skip on web - if (Platform.OS === 'web') { - logger.debug({ message: 'Push notification service skipped on web' }); - return; - } + // Notification tap (background → foreground) via expo-notifications. + private handleNotificationResponse = (response: Notifications.NotificationResponse): void => { + const content = response.notification.request.content; + const data = content.data as Record | undefined; - // Set up notification channels/categories based on platform - await this.setupAndroidNotificationChannels(); - await this.setupIOSNotificationCategories(); + logger.info({ + message: 'Notification response received (tap)', + context: { data, actionIdentifier: response.actionIdentifier }, + }); - // Set up Notifee event listeners for notification taps - notifee.onForegroundEvent(async ({ type, detail }) => { + // Delay so the React tree is mounted and the modal store is ready. + setTimeout(() => { + this.showModalForData(data, content.title, content.body); + }, TAP_BACKGROUND_DELAY_MS); + }; + + // Notifee events handle taps/actions on notifee-displayed notifications, + // including the check-in action surfaced by the check-in timer feature. + private setupNotifeeEvents(): void { + this.notifeeForegroundUnsubscribe = notifee.onForegroundEvent(async ({ type, detail }) => { logger.info({ message: 'Notifee foreground event', context: { type, detail: { id: detail.notification?.id, data: detail.notification?.data } }, @@ -197,51 +195,12 @@ class PushNotificationService { // Handle check-in action press if (type === EventType.ACTION_PRESS && detail.pressAction?.id === 'check-in') { - logger.info({ message: 'Check-in action pressed from notification' }); - const activeCall = useCoreStore.getState().activeCall; - const activeUnit = useCoreStore.getState().activeUnit; - if (activeCall) { - const callId = parseInt(activeCall.CallId, 10); - if (Number.isNaN(callId)) { - logger.error({ message: 'Check-in action aborted: invalid CallId', context: { CallId: activeCall.CallId } }); - } else { - const unitId = activeUnit ? parseInt(activeUnit.UnitId, 10) : undefined; - if (activeUnit && Number.isNaN(unitId)) { - logger.error({ message: 'Check-in action aborted: invalid UnitId', context: { UnitId: activeUnit.UnitId } }); - } else { - await useCheckInTimerStore.getState().performCheckIn({ - CallId: callId, - CheckInType: activeUnit ? CHECK_IN_TYPE_UNIT : CHECK_IN_TYPE_PERSONNEL, - UnitId: unitId, - Latitude: useLocationStore.getState().latitude?.toString(), - Longitude: useLocationStore.getState().longitude?.toString(), - }); - } - } - } + await this.handleCheckInAction(); } - // Handle notification press + // Handle notification press → modal if (type === EventType.PRESS && detail.notification) { - const eventCode = detail.notification.data?.eventCode as string | undefined; - const title = detail.notification.title; - const body = detail.notification.body; - - if (eventCode && typeof eventCode === 'string') { - const notificationData = { - eventCode: eventCode, - title: title, - body: body, - data: detail.notification.data, - }; - - logger.info({ - message: 'Showing notification modal from Notifee foreground tap', - context: { eventCode, title }, - }); - - await usePushNotificationModalStore.getState().showNotificationModal(notificationData); - } + this.showModalForData(detail.notification.data, detail.notification.title, detail.notification.body); } }); @@ -251,157 +210,91 @@ class PushNotificationService { context: { type, detail: { id: detail.notification?.id, data: detail.notification?.data } }, }); - // Handle notification press in background - if (type === EventType.PRESS && detail.notification) { - const eventCode = detail.notification.data?.eventCode as string | undefined; - const title = detail.notification.title; - const body = detail.notification.body; - - if (eventCode && typeof eventCode === 'string') { - const notificationData = { - eventCode: eventCode, - title: title, - body: body, - data: detail.notification.data, - }; - - logger.info({ - message: 'Showing notification modal from Notifee background tap', - context: { eventCode, title }, - }); + if (type === EventType.ACTION_PRESS && detail.pressAction?.id === 'check-in') { + await this.handleCheckInAction(); + } - await usePushNotificationModalStore.getState().showNotificationModal(notificationData); - } + if (type === EventType.PRESS && detail.notification) { + this.showModalForData(detail.notification.data, detail.notification.title, detail.notification.body); } }); + } - // Register background message handler (only once) - if (!this.backgroundMessageHandlerRegistered) { - messaging().setBackgroundMessageHandler(async (remoteMessage: any) => { - logger.info({ - message: 'Background FCM message received', - context: { - data: remoteMessage.data, - notification: remoteMessage.notification, - }, - }); + private async handleCheckInAction(): Promise { + logger.info({ message: 'Check-in action pressed from notification' }); + const activeCall = useCoreStore.getState().activeCall; + const activeUnit = useCoreStore.getState().activeUnit; + if (!activeCall) { + return; + } - // For iOS background notifications, display using Notifee - if (Platform.OS === 'ios' && remoteMessage.notification) { - const customType = remoteMessage.data?.type || remoteMessage.data?.customType; - const category = remoteMessage.data?.category || remoteMessage.notification?.android?.channelId || 'calls'; - const title = (remoteMessage.data?.title as string) || remoteMessage.notification.title; - const body = (remoteMessage.data?.message as string) || remoteMessage.notification.body; - const isCritical = category === 'calls' || customType === '0'; - - // Derive sound from remoteMessage.data['sound'] or remoteMessage.notification?.ios?.sound, fallback to 'default' - const soundName = String(remoteMessage.data?.sound || remoteMessage.notification?.ios?.sound || 'default'); - - await notifee.displayNotification({ - title: title, - body: body, - ios: { - sound: soundName, - criticalVolume: 1.0, - critical: isCritical, - categoryId: (category as string) || 'calls', - }, - data: remoteMessage.data as Record, - }); - } - }); - this.backgroundMessageHandlerRegistered = true; + const callId = parseInt(activeCall.CallId, 10); + if (Number.isNaN(callId)) { + logger.error({ message: 'Check-in action aborted: invalid CallId', context: { CallId: activeCall.CallId } }); + return; } - // Listen for foreground messages and store the unsubscribe function - this.fcmOnMessageUnsubscribe = messaging().onMessage(this.handleRemoteMessage); + const unitId = activeUnit ? parseInt(activeUnit.UnitId, 10) : undefined; + if (activeUnit && Number.isNaN(unitId)) { + logger.error({ message: 'Check-in action aborted: invalid UnitId', context: { UnitId: activeUnit.UnitId } }); + return; + } - // Listen for notification opened app (when user taps on notification) - this.fcmOnNotificationOpenedAppUnsubscribe = messaging().onNotificationOpenedApp((remoteMessage: any) => { - logger.info({ - message: 'Notification opened app (from background)', - context: { - data: remoteMessage.data, - notification: remoteMessage.notification, - }, - }); + await useCheckInTimerStore.getState().performCheckIn({ + CallId: callId, + CheckInType: activeUnit ? CHECK_IN_TYPE_UNIT : CHECK_IN_TYPE_PERSONNEL, + UnitId: unitId, + Latitude: useLocationStore.getState().latitude?.toString(), + Longitude: useLocationStore.getState().longitude?.toString(), + }); + } - // Extract eventCode and other data - const eventCode = remoteMessage.data?.eventCode as string | undefined; - const title = (remoteMessage.data?.title as string) || remoteMessage.notification?.title; - const body = (remoteMessage.data?.message as string) || remoteMessage.notification?.body; - - // Handle notification tap - // Use a small delay to ensure the app is fully initialized and the store is ready - setTimeout(async () => { - if (eventCode && typeof eventCode === 'string') { - const notificationData = { - eventCode: eventCode, - title: title, - body: body, - data: remoteMessage.data, - }; + async initialize(): Promise { + // Push notifications are native-only; skip on web + if (Platform.OS === 'web') { + logger.debug({ message: 'Push notification service skipped on web' }); + return; + } - logger.info({ - message: 'Showing notification modal from tap (background)', - context: { eventCode, title }, - }); + // Register expo-notifications listeners synchronously so taps/receipts that + // arrive during startup are not missed. + this.notificationListener = Notifications.addNotificationReceivedListener(this.handleNotificationReceived); + this.responseListener = Notifications.addNotificationResponseReceivedListener(this.handleNotificationResponse); - // Show the notification modal using the store - await usePushNotificationModalStore.getState().showNotificationModal(notificationData); - } - }, 300); - }); + // Set up notification channels/categories based on platform + await this.setupAndroidNotificationChannels(); + await this.setupIOSNotificationCategories(); - // Check if app was opened from a notification (when app was killed) - // Use a longer delay to ensure React tree is fully mounted - setTimeout(() => { - messaging() - .getInitialNotification() - .then((remoteMessage: any) => { - if (remoteMessage) { - logger.info({ - message: 'App opened from notification (killed state)', - context: { - data: remoteMessage.data, - notification: remoteMessage.notification, - }, - }); + // Notifee events (check-in action + notifee-displayed taps) + this.setupNotifeeEvents(); - // Extract eventCode and other data - const eventCode = remoteMessage.data?.eventCode as string | undefined; - const title = (remoteMessage.data?.title as string) || remoteMessage.notification?.title; - const body = (remoteMessage.data?.message as string) || remoteMessage.notification?.body; - - // Handle the initial notification - // Use a delay to ensure the app is fully loaded and the store is ready - setTimeout(async () => { - if (eventCode && typeof eventCode === 'string') { - const notificationData = { - eventCode: eventCode, - title: title, - body: body, - data: remoteMessage.data, - }; - - logger.info({ - message: 'Showing notification modal from tap (killed state)', - context: { eventCode, title }, - }); - - // Show the notification modal using the store - await usePushNotificationModalStore.getState().showNotificationModal(notificationData); - } - }, 500); + // Handle the notification that launched the app from a killed state. + // expo-notifications surfaces this via getLastNotificationResponseAsync(). + setTimeout(() => { + Notifications.getLastNotificationResponseAsync() + .then((response) => { + if (!response) { + return; } + const content = response.notification.request.content; + const data = content.data as Record | undefined; + + logger.info({ + message: 'App opened from notification (killed state)', + context: { data }, + }); + + setTimeout(() => { + this.showModalForData(data, content.title, content.body); + }, TAP_KILLED_MODAL_DELAY_MS); }) - .catch((error: any) => { + .catch((error) => { logger.error({ message: 'Error checking initial notification', context: { error }, }); }); - }, 1000); + }, TAP_KILLED_INITIAL_DELAY_MS); logger.info({ message: 'Push notification service initialized', @@ -424,76 +317,49 @@ class PushNotificationService { } try { - // Request permissions based on platform - if (Platform.OS === 'ios') { - // For iOS, request permissions using Firebase Messaging - let authStatus = await messaging().hasPermission(); - - if (authStatus === messaging.AuthorizationStatus.NOT_DETERMINED || authStatus === messaging.AuthorizationStatus.DENIED) { - // Request permission - authStatus = await messaging().requestPermission({ - alert: true, - badge: true, - sound: true, - criticalAlert: true, // iOS critical alerts - provisional: false, - }); - } - - // Check if permission was granted - const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED || authStatus === messaging.AuthorizationStatus.PROVISIONAL; + // Request OS notification permissions (iOS critical alerts included). + const { status: existingStatus } = await Notifications.getPermissionsAsync(); + let finalStatus = existingStatus; - if (!enabled) { - logger.warn({ - message: 'Failed to get push notification permissions', - context: { authStatus }, - }); - return null; - } - - // Also request Notifee permissions for iOS to enable critical alerts - await notifee.requestPermission({ - alert: true, - badge: true, - sound: true, - criticalAlert: true, + if (existingStatus !== 'granted') { + const { status } = await Notifications.requestPermissionsAsync({ + ios: { + allowAlert: true, + allowBadge: true, + allowSound: true, + allowCriticalAlerts: true, + }, }); - } else { - // For Android, request permissions using Firebase Messaging - let authStatus = await messaging().hasPermission(); - - if (authStatus === messaging.AuthorizationStatus.NOT_DETERMINED || authStatus === messaging.AuthorizationStatus.DENIED) { - authStatus = await messaging().requestPermission({ - alert: true, - badge: true, - sound: true, - }); - } - - const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED || authStatus === messaging.AuthorizationStatus.PROVISIONAL; + finalStatus = status; + } - if (!enabled) { - logger.warn({ - message: 'Failed to get push notification permissions', - context: { authStatus }, - }); - return null; - } + if (finalStatus !== 'granted') { + logger.warn({ + message: 'Failed to get push notification permissions', + context: { status: finalStatus }, + }); + return null; + } - // For Android, also request notification permission using Notifee - const notifeeSettings = await notifee.requestPermission(); - if (notifeeSettings.authorizationStatus === AuthorizationStatus.DENIED) { - logger.warn({ - message: 'Notifee notification permissions denied', - context: { authorizationStatus: notifeeSettings.authorizationStatus }, - }); - return null; - } + // Also request Notifee permissions so notifee-managed channels/critical + // alerts are authorized on both platforms. + const notifeeSettings = await notifee.requestPermission({ + alert: true, + badge: true, + sound: true, + criticalAlert: true, + }); + if (notifeeSettings.authorizationStatus === AuthorizationStatus.DENIED) { + logger.warn({ + message: 'Notifee notification permissions denied', + context: { authorizationStatus: notifeeSettings.authorizationStatus }, + }); + return null; } - // Get FCM token - const token = await messaging().getToken(); - this.pushToken = token; + // Get the native device push token (FCM on Android, APNs on iOS). + const devicePushToken = await Notifications.getDevicePushTokenAsync(); + this.pushToken = devicePushToken.data as string; logger.info({ message: 'Push notification token obtained', @@ -528,14 +394,19 @@ class PushNotificationService { } public cleanup(): void { - if (this.fcmOnMessageUnsubscribe) { - this.fcmOnMessageUnsubscribe(); - this.fcmOnMessageUnsubscribe = null; + if (this.notificationListener) { + this.notificationListener.remove(); + this.notificationListener = null; + } + + if (this.responseListener) { + this.responseListener.remove(); + this.responseListener = null; } - if (this.fcmOnNotificationOpenedAppUnsubscribe) { - this.fcmOnNotificationOpenedAppUnsubscribe(); - this.fcmOnNotificationOpenedAppUnsubscribe = null; + if (this.notifeeForegroundUnsubscribe) { + this.notifeeForegroundUnsubscribe(); + this.notifeeForegroundUnsubscribe = null; } } } diff --git a/src/types/declarations.d.ts b/src/types/declarations.d.ts index d882472..ddfce4c 100644 --- a/src/types/declarations.d.ts +++ b/src/types/declarations.d.ts @@ -1,7 +1,6 @@ declare module 'countly-sdk-react-native-bridge'; declare module 'countly-sdk-react-native-bridge/CountlyConfig'; declare module 'react-native-callkeep'; -declare module '@react-native-firebase/messaging'; declare module 'mapbox-gl'; declare module 'react-dom'; declare module '*.css'; diff --git a/yarn.lock b/yarn.lock index d0c1556..dc85961 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1787,397 +1787,6 @@ find-up "^5.0.0" js-yaml "^4.1.0" -"@firebase/ai@2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@firebase/ai/-/ai-2.4.0.tgz#fe67130f8b8770aa74c028f511dc61b67440a30a" - integrity sha512-YilG6AJ/nYpCKtxZyvEzBRAQv5bU+2tBOKX4Ps0rNNSdxN39aT37kGhjATbk1kq1z5Lq7mkWglw/ajAF3lOWUg== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/analytics-compat@0.2.25": - version "0.2.25" - resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.25.tgz#1f48bb6237bed7d6a3cf8136957aa5ceb245507b" - integrity sha512-fdzoaG0BEKbqksRDhmf4JoyZf16Wosrl0Y7tbZtJyVDOOwziE0vrFjmZuTdviL0yhak+Nco6rMsUUbkbD+qb6Q== - dependencies: - "@firebase/analytics" "0.10.19" - "@firebase/analytics-types" "0.8.3" - "@firebase/component" "0.7.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/analytics-types@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.3.tgz#d08cd39a6209693ca2039ba7a81570dfa6c1518f" - integrity sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg== - -"@firebase/analytics@0.10.19": - version "0.10.19" - resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.19.tgz#6bddeb9db287fa2367066855b12ec514e2914697" - integrity sha512-3wU676fh60gaiVYQEEXsbGS4HbF2XsiBphyvvqDbtC1U4/dO4coshbYktcCHq+HFaGIK07iHOh4pME0hEq1fcg== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/installations" "0.6.19" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/app-check-compat@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.4.0.tgz#94ac0cf9f66cab1d81a7b14e0c151dcc2684bc95" - integrity sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g== - dependencies: - "@firebase/app-check" "0.11.0" - "@firebase/app-check-types" "0.5.3" - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/app-check-interop-types@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz#ed9c4a4f48d1395ef378f007476db3940aa5351a" - integrity sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A== - -"@firebase/app-check-types@0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.3.tgz#38ba954acf4bffe451581a32fffa20337f11d8e5" - integrity sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng== - -"@firebase/app-check@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.11.0.tgz#a7e1d1e3f5ae36eabed1455db937114fe869ce8f" - integrity sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/app-compat@0.5.4": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.5.4.tgz#eb8f47d51c57887c9979279d4d39e4ee85270fe4" - integrity sha512-T7ifGmb+awJEcp542Ek4HtNfBxcBrnuk1ggUdqyFEdsXHdq7+wVlhvE6YukTL7NS8hIkEfL7TMAPx/uCNqt30g== - dependencies: - "@firebase/app" "0.14.4" - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/app-types@0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.3.tgz#8408219eae9b1fb74f86c24e7150a148460414ad" - integrity sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw== - -"@firebase/app@0.14.4": - version "0.14.4" - resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.14.4.tgz#1d2ce74c09752dec9664e2f981b20335c4efbec1" - integrity sha512-pUxEGmR+uu21OG/icAovjlu1fcYJzyVhhT0rsCrn+zi+nHtrS43Bp9KPn9KGa4NMspCUE++nkyiqziuIvJdwzw== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/auth-compat@0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.6.0.tgz#1464ea6049b2ad0aae83b4fdcd5e5e5aba6b1c50" - integrity sha512-J0lGSxXlG/lYVi45wbpPhcWiWUMXevY4fvLZsN1GHh+po7TZVng+figdHBVhFheaiipU8HZyc7ljw1jNojM2nw== - dependencies: - "@firebase/auth" "1.11.0" - "@firebase/auth-types" "0.13.0" - "@firebase/component" "0.7.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/auth-interop-types@0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz#176a08686b0685596ff03d7879b7e4115af53de0" - integrity sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA== - -"@firebase/auth-types@0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.13.0.tgz#ae6e0015e3bd4bfe18edd0942b48a0a118a098d9" - integrity sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg== - -"@firebase/auth@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-1.11.0.tgz#81a4f77b16d97c502e493b2a14a97443e243a2a0" - integrity sha512-5j7+ua93X+IRcJ1oMDTClTo85l7Xe40WSkoJ+shzPrX7OISlVWLdE1mKC57PSD+/LfAbdhJmvKixINBw2ESK6w== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/component@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.7.0.tgz#3736644fdb6d3572dceae7fdc1c35a8bd3819adc" - integrity sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg== - dependencies: - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/data-connect@0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@firebase/data-connect/-/data-connect-0.3.11.tgz#60a7a9649e4aedd005546032466ef9abc0a544c1" - integrity sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw== - dependencies: - "@firebase/auth-interop-types" "0.2.4" - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/database-compat@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-2.1.0.tgz#c64488d741c6da2ed8dcf02f2e433089dae2f590" - integrity sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/database" "1.1.0" - "@firebase/database-types" "1.0.16" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/database-types@1.0.16": - version "1.0.16" - resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.16.tgz#262f54b8dbebbc46259757b3ba384224fb2ede48" - integrity sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw== - dependencies: - "@firebase/app-types" "0.9.3" - "@firebase/util" "1.13.0" - -"@firebase/database@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.1.0.tgz#bdf60f1605079a87ceb2b5e30d90846e0bde294b" - integrity sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/auth-interop-types" "0.2.4" - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - faye-websocket "0.11.4" - tslib "^2.1.0" - -"@firebase/firestore-compat@0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.4.2.tgz#2c9f5bef1dff004ae2db5759608f17d7973da78c" - integrity sha512-cy7ov6SpFBx+PHwFdOOjbI7kH00uNKmIFurAn560WiPCZXy9EMnil1SOG7VF4hHZKdenC+AHtL4r3fNpirpm0w== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/firestore" "4.9.2" - "@firebase/firestore-types" "3.0.3" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/firestore-types@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.3.tgz#7d0c3dd8850c0193d8f5ee0cc8f11961407742c1" - integrity sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q== - -"@firebase/firestore@4.9.2": - version "4.9.2" - resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.9.2.tgz#0c65203f9754d5aa801ec31c6f885445cfb346f4" - integrity sha512-iuA5+nVr/IV/Thm0Luoqf2mERUvK9g791FZpUJV1ZGXO6RL2/i/WFJUj5ZTVXy5pRjpWYO+ZzPcReNrlilmztA== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - "@firebase/webchannel-wrapper" "1.0.5" - "@grpc/grpc-js" "~1.9.0" - "@grpc/proto-loader" "^0.7.8" - tslib "^2.1.0" - -"@firebase/functions-compat@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.4.1.tgz#b253b761845f0c82bbdf76ef59975978ed84eb65" - integrity sha512-AxxUBXKuPrWaVNQ8o1cG1GaCAtXT8a0eaTDfqgS5VsRYLAR0ALcfqDLwo/QyijZj1w8Qf8n3Qrfy/+Im245hOQ== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/functions" "0.13.1" - "@firebase/functions-types" "0.6.3" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/functions-types@0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.3.tgz#f5faf770248b13f45d256f614230da6a11bfb654" - integrity sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg== - -"@firebase/functions@0.13.1": - version "0.13.1" - resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.13.1.tgz#472e8456568689154b87a494ee8c10ee2e610d94" - integrity sha512-sUeWSb0rw5T+6wuV2o9XNmh9yHxjFI9zVGFnjFi+n7drTEWpl7ZTz1nROgGrSu472r+LAaj+2YaSicD4R8wfbw== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/auth-interop-types" "0.2.4" - "@firebase/component" "0.7.0" - "@firebase/messaging-interop-types" "0.2.3" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/installations-compat@0.2.19": - version "0.2.19" - resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.19.tgz#4bc57c8c57d241eeca95900ff3033d6ec3dbcc7c" - integrity sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/installations" "0.6.19" - "@firebase/installations-types" "0.5.3" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/installations-types@0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.3.tgz#cac8a14dd49f09174da9df8ae453f9b359c3ef2f" - integrity sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA== - -"@firebase/installations@0.6.19": - version "0.6.19" - resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.19.tgz#93c569321f6fb399f4f1a197efc0053ce6452c7c" - integrity sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/util" "1.13.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/logger@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.5.0.tgz#a9e55b1c669a0983dc67127fa4a5964ce8ed5e1b" - integrity sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g== - dependencies: - tslib "^2.1.0" - -"@firebase/messaging-compat@0.2.23": - version "0.2.23" - resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.23.tgz#2ca6b36ea238fae4dff53bf85442c4a2af516224" - integrity sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/messaging" "0.12.23" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/messaging-interop-types@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz#e647c9cd1beecfe6a6e82018a6eec37555e4da3e" - integrity sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q== - -"@firebase/messaging@0.12.23": - version "0.12.23" - resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.23.tgz#71f932a521ac39d9f036175672e37897531010eb" - integrity sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/installations" "0.6.19" - "@firebase/messaging-interop-types" "0.2.3" - "@firebase/util" "1.13.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/performance-compat@0.2.22": - version "0.2.22" - resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.22.tgz#1c24ea360b03cfef831bdf379b4fc7080f412741" - integrity sha512-xLKxaSAl/FVi10wDX/CHIYEUP13jXUjinL+UaNXT9ByIvxII5Ne5150mx6IgM8G6Q3V+sPiw9C8/kygkyHUVxg== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/performance" "0.7.9" - "@firebase/performance-types" "0.2.3" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/performance-types@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.3.tgz#5ce64e90fa20ab5561f8b62a305010cf9fab86fb" - integrity sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ== - -"@firebase/performance@0.7.9": - version "0.7.9" - resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.7.9.tgz#7e3a072b1542f0df3f502684a38a0516b0d72cab" - integrity sha512-UzybENl1EdM2I1sjYm74xGt/0JzRnU/0VmfMAKo2LSpHJzaj77FCLZXmYQ4oOuE+Pxtt8Wy2BVJEENiZkaZAzQ== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/installations" "0.6.19" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - web-vitals "^4.2.4" - -"@firebase/remote-config-compat@0.2.20": - version "0.2.20" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.20.tgz#4bca09b1361867d0c882411970486ee06622e071" - integrity sha512-P/ULS9vU35EL9maG7xp66uljkZgcPMQOxLj3Zx2F289baTKSInE6+YIkgHEi1TwHoddC/AFePXPpshPlEFkbgg== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/logger" "0.5.0" - "@firebase/remote-config" "0.7.0" - "@firebase/remote-config-types" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/remote-config-types@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz#f0f503b32edda3384f5252f9900cd9613adbb99c" - integrity sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg== - -"@firebase/remote-config@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.7.0.tgz#0e5e5879a7a9121c9da55606be8fa40ff70ddae1" - integrity sha512-dX95X6WlW7QlgNd7aaGdjAIZUiQkgWgNS+aKNu4Wv92H1T8Ue/NDUjZHd9xb8fHxLXIHNZeco9/qbZzr500MjQ== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/installations" "0.6.19" - "@firebase/logger" "0.5.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/storage-compat@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.4.0.tgz#a09bd33c262123e7e3ed0cd590b4c6e2ce4a8902" - integrity sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/storage" "0.14.0" - "@firebase/storage-types" "0.8.3" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/storage-types@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.3.tgz#2531ef593a3452fc12c59117195d6485c6632d3d" - integrity sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg== - -"@firebase/storage@0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.14.0.tgz#01acb97d413ada7c91de860fb260623468baa25d" - integrity sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA== - dependencies: - "@firebase/component" "0.7.0" - "@firebase/util" "1.13.0" - tslib "^2.1.0" - -"@firebase/util@1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.13.0.tgz#2e9e7569722a1e3fc86b1b4076d5cbfbfa7265d6" - integrity sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ== - dependencies: - tslib "^2.1.0" - -"@firebase/webchannel-wrapper@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz#39cf5a600450cb42f1f0b507cc385459bf103b27" - integrity sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw== - "@floating-ui/core@^1.6.0", "@floating-ui/core@^1.7.3": version "1.7.3" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7" @@ -2591,24 +2200,6 @@ dependencies: nanoid "^3.3.1" -"@grpc/grpc-js@~1.9.0": - version "1.9.15" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.15.tgz#433d7ac19b1754af690ea650ab72190bd700739b" - integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== - dependencies: - "@grpc/proto-loader" "^0.7.8" - "@types/node" ">=12.12.47" - -"@grpc/proto-loader@^0.7.8": - version "0.7.15" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60" - integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ== - dependencies: - lodash.camelcase "^4.3.0" - long "^5.0.0" - protobufjs "^7.2.5" - yargs "^17.7.2" - "@hapi/address@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-5.1.1.tgz#e9925fc1b65f5cc3fbea821f2b980e4652e84cb6" @@ -2685,6 +2276,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== +"@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== + "@inquirer/external-editor@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@inquirer/external-editor/-/external-editor-1.0.2.tgz#dc16e7064c46c53be09918db639ff780718c071a" @@ -3694,59 +3290,6 @@ "@pnpm/network.ca-file" "^1.0.1" config-chain "^1.1.11" -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== - "@radix-ui/primitive@1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.3.tgz#e2dbc13bdc5e4168f4334f75832d7bdd3e2de5ba" @@ -4250,18 +3793,6 @@ resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-11.4.1.tgz#a3c247aceab35f75dd0aa4bfa85d2be5a4508688" integrity sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg== -"@react-native-firebase/app@23.5.0": - version "23.5.0" - resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-23.5.0.tgz#b84540b1822e510dfd3c3890e8ca10b2655759fe" - integrity sha512-TOlm6V6fbILwgFP37QZM9Y0nfAW6zqNGVIWlMlepQB6b/BzzFMrCl1FiyknqD5l7i1jgdFQrqX1WH6ZO4ePa/g== - dependencies: - firebase "12.4.0" - -"@react-native-firebase/messaging@23.5.0": - version "23.5.0" - resolved "https://registry.yarnpkg.com/@react-native-firebase/messaging/-/messaging-23.5.0.tgz#8e39a44a90f7bf95a9a167649efa7f1e8251f9b7" - integrity sha512-2EM28isDWgqCauar/kOnhpFQZ8ARnq9iE0N093TrS/sr+Mu6PHkPEDJElV9LFfp6nfxxjlm75h+x+nJrEDRkhQ== - "@react-native/assets-registry@0.81.5": version "0.81.5" resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.81.5.tgz#d22c924fa6f6d4a463c5af34ce91f38756c0fa7d" @@ -5724,13 +5255,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g== -"@types/node@>=12.12.47", "@types/node@>=13.7.0": - version "24.9.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-24.9.2.tgz#90ded2422dbfcafcf72080f28975adc21366148d" - integrity sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA== - dependencies: - undici-types "~7.16.0" - "@types/node@^24.9.0": version "24.10.9" resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.9.tgz#1aeb5142e4a92957489cac12b07f9c7fe26057d0" @@ -6571,6 +6095,17 @@ assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== +assert@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -6840,6 +6375,11 @@ babel-preset-jest@^29.6.3: babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" +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" @@ -7128,6 +6668,16 @@ call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply- es-errors "^1.3.0" function-bind "^1.1.2" +call-bind@^1.0.0, call-bind@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.9.tgz#39a644700c80bc7d0ca9102fc6d1d43b2fd7eee7" + integrity sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + get-intrinsic "^1.3.0" + set-function-length "^1.2.2" + call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" @@ -9406,6 +8956,19 @@ expo-navigation-bar@5.0.10: debug "^4.3.2" react-native-is-edge-to-edge "^1.2.1" +expo-notifications@0.32.16: + version "0.32.16" + resolved "https://registry.yarnpkg.com/expo-notifications/-/expo-notifications-0.32.16.tgz#1a1304b89efedd7cdeba92de39b21f09fb2db2c7" + integrity sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw== + dependencies: + "@expo/image-utils" "^0.8.8" + "@ide/backoff" "^1.0.0" + abort-controller "^3.0.0" + assert "^2.0.0" + badgin "^1.1.5" + expo-application "~7.0.8" + expo-constants "~18.0.13" + expo-router@6.0.23: version "6.0.23" resolved "https://registry.yarnpkg.com/expo-router/-/expo-router-6.0.23.tgz#480fbcb4901fd692f9d11762f33894280dcbd75a" @@ -9594,13 +9157,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -faye-websocket@0.11.4: - version "0.11.4" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" - integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== - dependencies: - websocket-driver ">=0.5.1" - fb-watchman@^2.0.0, fb-watchman@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" @@ -9774,40 +9330,6 @@ find-yarn-workspace-root@^2.0.0: dependencies: micromatch "^4.0.2" -firebase@12.4.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-12.4.0.tgz#c9de52c23e707d90aa43343ab3ad1c1ce6b71301" - integrity sha512-/chNgDQ6ppPPGOQO4jctxOa/5JeQxuhaxA7Y90K0I+n/wPfoO8mRveedhVUdo7ExLcWUivnnow/ouSLYSI5Icw== - dependencies: - "@firebase/ai" "2.4.0" - "@firebase/analytics" "0.10.19" - "@firebase/analytics-compat" "0.2.25" - "@firebase/app" "0.14.4" - "@firebase/app-check" "0.11.0" - "@firebase/app-check-compat" "0.4.0" - "@firebase/app-compat" "0.5.4" - "@firebase/app-types" "0.9.3" - "@firebase/auth" "1.11.0" - "@firebase/auth-compat" "0.6.0" - "@firebase/data-connect" "0.3.11" - "@firebase/database" "1.1.0" - "@firebase/database-compat" "2.1.0" - "@firebase/firestore" "4.9.2" - "@firebase/firestore-compat" "0.4.2" - "@firebase/functions" "0.13.1" - "@firebase/functions-compat" "0.4.1" - "@firebase/installations" "0.6.19" - "@firebase/installations-compat" "0.2.19" - "@firebase/messaging" "0.12.23" - "@firebase/messaging-compat" "0.2.23" - "@firebase/performance" "0.7.9" - "@firebase/performance-compat" "0.2.22" - "@firebase/remote-config" "0.7.0" - "@firebase/remote-config-compat" "0.2.20" - "@firebase/storage" "0.14.0" - "@firebase/storage-compat" "0.4.0" - "@firebase/util" "1.13.0" - flat-cache@^3.0.4: version "3.2.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" @@ -10480,11 +10002,6 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -http-parser-js@>=0.5.1: - version "0.5.10" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.10.tgz#b3277bd6d7ed5588e20ea73bf724fcbe44609075" - integrity sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA== - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -10577,11 +10094,6 @@ iconv-lite@^0.7.0: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -idb@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" - integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== - ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -10795,7 +10307,7 @@ irregular-plurals@^1.0.0: resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766" integrity sha512-kniTIJmaZYiwa17eTtWIfm0K342seyugl6vuC8DiiyiRAJWAVlLkqGCI0Im0neo0TkXw+pRcKaBPRdcKHnQJ6Q== -is-arguments@^1.1.1: +is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b" integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== @@ -10977,6 +10489,17 @@ is-generator-function@^1.0.10: has-tostringtag "^1.0.2" safe-regex-test "^1.1.0" +is-generator-function@^1.0.7: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.2.tgz#ae3b61e3d5ea4e4839b90bad22b02335051a17d5" + integrity sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA== + dependencies: + call-bound "^1.0.4" + generator-function "^2.0.0" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -11019,6 +10542,14 @@ is-map@^2.0.2, is-map@^2.0.3: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== +is-nan@^1.3.2: + 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.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" @@ -11147,7 +10678,7 @@ is-text-path@^2.0.0: dependencies: text-extensions "^2.0.0" -is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15, is-typed-array@^1.1.3: version "1.1.15" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== @@ -12538,11 +12069,6 @@ loglevel@^1.8.0, loglevel@^1.9.2: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== -long@^5.0.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" - integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== - loose-envify@^1.0.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -13677,6 +13203,14 @@ object-inspect@^1.13.3, object-inspect@^1.13.4: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -14496,24 +14030,6 @@ proto-list@~1.2.1: resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -protobufjs@^7.2.5: - version "7.5.4" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" - integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - protocol-buffers-schema@^3.3.1: version "3.6.0" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" @@ -15403,7 +14919,7 @@ safe-array-concat@^1.1.3: has-symbols "^1.1.0" isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -17162,6 +16678,17 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.12.5: + 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" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -17277,11 +16804,6 @@ web-streams-polyfill@^4.1.0: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.2.0.tgz#93295e67af95889a1e044a6beff1366c82720650" integrity sha512-0rYDzGOh9EZpig92umN5g5D/9A1Kff7k0/mzPSSCY8jEQeYkgRMoY7LhbXtUCWzLCMX0TUE9aoHkjFNB7D9pfA== -web-vitals@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" - integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -17304,20 +16826,6 @@ webrtc-adapter@^9.0.1: dependencies: sdp "^3.2.0" -websocket-driver@>=0.5.1: - version "0.7.4" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - well-known-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/well-known-symbols/-/well-known-symbols-4.1.0.tgz#7f748817d7bfdd4a95395127a056ce5205910624" @@ -17426,6 +16934,19 @@ which-typed-array@^1.1.16, which-typed-array@^1.1.19: gopd "^1.2.0" has-tostringtag "^1.0.2" +which-typed-array@^1.1.2: + version "1.1.22" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.22.tgz#8f3cc78aefb40b437346dd40a1dbfa5d1da43fe9" + integrity sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.9" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -17679,7 +17200,7 @@ yargs-parser@^21.0.1, yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@17.7.2, yargs@^17.0.0, yargs@^17.0.1, yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.2: +yargs@17.7.2, yargs@^17.0.0, yargs@^17.0.1, yargs@^17.3.1, yargs@^17.6.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==