From e6d57f0a18e256636f6683da67c833903735d0eb Mon Sep 17 00:00:00 2001 From: Wade King Date: Tue, 6 Aug 2024 13:45:32 -0700 Subject: [PATCH] feat: refactored notifications (#2110) Signed-off-by: wadeking98 --- .../screens/PersonCredential.test.tsx | 4 +- app/container-imp.ts | 44 +++--- app/ios/Podfile.lock | 4 +- app/package.json | 10 +- app/src/constants.ts | 6 +- app/src/helpers/BCIDHelper.ts | 1 - app/src/hooks/notifications.ts | 143 ++++++++---------- app/src/index.ts | 2 - app/src/screens/PersonCredential.tsx | 14 +- app/src/screens/PersonCredentialLoading.tsx | 1 + app/src/services/attestation.ts | 10 +- yarn.lock | 50 +++--- 12 files changed, 138 insertions(+), 151 deletions(-) diff --git a/app/__tests__/screens/PersonCredential.test.tsx b/app/__tests__/screens/PersonCredential.test.tsx index 2c7a89ac3..4a1f46968 100644 --- a/app/__tests__/screens/PersonCredential.test.tsx +++ b/app/__tests__/screens/PersonCredential.test.tsx @@ -4,6 +4,7 @@ import React from 'react' import PersonCredential from '../../src/screens/PersonCredential' import { initialState, reducer } from '../../src/store' +import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' const mockNavigation = jest.fn() jest.mock('@react-navigation/native', () => ({ @@ -43,9 +44,10 @@ describe('Person Credential Screen', () => { }) test('screen renders correctly', () => { + const navigation = useNavigation() const tree = render( - + ) diff --git a/app/container-imp.ts b/app/container-imp.ts index 1de4d6809..929520c10 100644 --- a/app/container-imp.ts +++ b/app/container-imp.ts @@ -31,6 +31,7 @@ import { DependencyContainer } from 'tsyringe' import { autoDisableRemoteLoggingIntervalInMinutes } from './src/constants' import { expirationOverrideInMinutes } from './src/helpers/utils' +import { useNotifications } from './src/hooks/notifications' import Developer from './src/screens/Developer' import PersonCredential from './src/screens/PersonCredential' import PersonCredentialLoading from './src/screens/PersonCredentialLoading' @@ -166,27 +167,30 @@ export class AppContainer implements Container { }) this._container.registerInstance(TOKENS.UTIL_OCA_RESOLVER, resolver) - this._container.registerInstance(TOKENS.CUSTOM_NOTIFICATION, { - component: PersonCredential, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onCloseAction: (dispatch?: React.Dispatch>) => { - if (dispatch) { - dispatch({ - type: BCDispatchAction.PERSON_CREDENTIAL_OFFER_DISMISSED, - payload: [{ personCredentialOfferDismissed: true }], - }) - } - }, - additionalStackItems: [ - { - component: PersonCredentialLoading, - name: 'PersonCredentialLoading', + this._container.registerInstance(TOKENS.NOTIFICATIONS, { + useNotifications, + customNotificationConfig: { + component: PersonCredential, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onCloseAction: (dispatch?: React.Dispatch>) => { + if (dispatch) { + dispatch({ + type: BCDispatchAction.PERSON_CREDENTIAL_OFFER_DISMISSED, + payload: [{ personCredentialOfferDismissed: true }], + }) + } }, - ], - pageTitle: 'PersonCredential.PageTitle', - title: 'PersonCredentialNotification.Title', - description: 'PersonCredentialNotification.Description', - buttonTitle: 'PersonCredentialNotification.ButtonTitle', + additionalStackItems: [ + { + component: PersonCredentialLoading, + name: 'PersonCredentialLoading', + }, + ], + pageTitle: 'PersonCredential.PageTitle', + title: 'PersonCredentialNotification.Title', + description: 'PersonCredentialNotification.Description', + buttonTitle: 'PersonCredentialNotification.ButtonTitle', + }, }) this._container.registerInstance(TOKENS.UTIL_PROOF_TEMPLATE, useProofRequestTemplates) diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 943930f84..019228fcc 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -445,7 +445,7 @@ PODS: - React-jsinspector (0.72.5) - React-logger (0.72.5): - glog - - "react-native-attestation (1.0.0-alpha.292+11561b58)": + - "react-native-attestation (1.0.0-alpha.295+b95c752a)": - RCT-Folly (= 2021.07.22.00) - React-Core - react-native-config (1.5.0): @@ -931,7 +931,7 @@ SPEC CHECKSUMS: React-jsiexecutor: ff70a72027dea5cc7d71cfcc6fad7f599f63987a React-jsinspector: aef73cbd43b70675f572214d10fa438c89bf11ba React-logger: 2e4aee3e11b3ec4fa6cfd8004610bbb3b8d6cca4 - react-native-attestation: e4e6f8bfba8246606cafbd3e77c9b33fc6cb98b6 + react-native-attestation: 190c81fbc066d101a947d6b9a73da6a455618a1c react-native-config: 5330c8258265c1e5fdb8c009d2cabd6badd96727 react-native-encrypted-storage: db300a3f2f0aba1e818417c1c0a6be549038deb7 react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a diff --git a/app/package.json b/app/package.json index badf56335..09e318f50 100644 --- a/app/package.json +++ b/app/package.json @@ -61,11 +61,11 @@ "@formatjs/intl-relativetimeformat": "9.3.1", "@hyperledger/anoncreds-react-native": "0.2.2", "@hyperledger/aries-askar-react-native": "0.2.3", - "@hyperledger/aries-bifold-core": "1.0.0-alpha.292", - "@hyperledger/aries-bifold-remote-logs": "1.0.0-alpha.292", - "@hyperledger/aries-bifold-verifier": "1.0.0-alpha.292", - "@hyperledger/aries-oca": "1.0.0-alpha.292", - "@hyperledger/aries-react-native-attestation": "1.0.0-alpha.292", + "@hyperledger/aries-bifold-core": "1.0.0-alpha.295", + "@hyperledger/aries-bifold-remote-logs": "1.0.0-alpha.295", + "@hyperledger/aries-bifold-verifier": "1.0.0-alpha.295", + "@hyperledger/aries-oca": "1.0.0-alpha.295", + "@hyperledger/aries-react-native-attestation": "1.0.0-alpha.295", "@hyperledger/indy-vdr-react-native": "0.2.2", "@hyperledger/indy-vdr-shared": "0.2.2", "@react-native-async-storage/async-storage": "1.15.11", diff --git a/app/src/constants.ts b/app/src/constants.ts index 26566402c..d7c5f3b19 100644 --- a/app/src/constants.ts +++ b/app/src/constants.ts @@ -2,7 +2,11 @@ export const autoDisableRemoteLoggingIntervalInMinutes = 60 export const surveyMonkeyUrl = 'https://www.surveymonkey.com/r/7BMHJL8' export const surveyMonkeyExitUrl = 'https://www.surveymonkey.com/survey-thanks' export const hitSlop = { top: 44, bottom: 44, left: 44, right: 44 } -export const AttestationRestrictions = { +interface AttestationRestrictionEnvironment { + credDefIDs: readonly string[] + invitationUrl: string +} +export const AttestationRestrictions: { [key: string]: AttestationRestrictionEnvironment } = { Development: { credDefIDs: ['NXp6XcGeCR2MviWuY51Dva:3:CL:33557:bcwallet', 'NXp6XcGeCR2MviWuY51Dva:3:CL:33557:bcwallet_dev_v2'], invitationUrl: diff --git a/app/src/helpers/BCIDHelper.ts b/app/src/helpers/BCIDHelper.ts index 8847a5a2f..bc5a82e4b 100644 --- a/app/src/helpers/BCIDHelper.ts +++ b/app/src/helpers/BCIDHelper.ts @@ -155,7 +155,6 @@ export const authenticateWithServiceCard = async ( forceCloseOnRedirection: false, showInRecents: true, }) - // When `result.type` is "Cancel" that comes from the alert box or // secure browser `result.url` will be undefined. if ( diff --git a/app/src/hooks/notifications.ts b/app/src/hooks/notifications.ts index 70e7fffc8..9214cc28c 100644 --- a/app/src/hooks/notifications.ts +++ b/app/src/hooks/notifications.ts @@ -21,102 +21,81 @@ import { AttestationRestrictions } from '../constants' import { showPersonCredentialSelector } from '../helpers/BCIDHelper' import { isProofRequestingAttestation } from '../services/attestation' import { BCState } from '../store' -interface CustomNotification { - type: 'CustomNotification' - createdAt: Date - id: string -} - -interface Notifications { - total: number - notifications: Array -} -export const useNotifications = (): Notifications => { +export const useNotifications = (): Array => { const { agent } = useAgent() const [store] = useStore() const offers = useCredentialByState(CredentialState.OfferReceived) const proofsRequested = useProofByState(ProofState.RequestReceived) const [nonAttestationProofs, setNonAttestationProofs] = useState([]) + const [notifications, setNotifications] = useState([]) const { records: basicMessages } = useBasicMessages() - // get all unseen messages - const unseenMessages: BasicMessageRecord[] = basicMessages.filter((msg) => { - const meta = msg.metadata.get(BasicMessageMetadata.customMetadata) as basicMessageCustomMetadata - return !meta?.seen - }) - // add one unseen message per contact to notifications - const contactsWithUnseenMessages: string[] = [] - const messagesToShow: BasicMessageRecord[] = [] - unseenMessages.forEach((msg) => { - if (!contactsWithUnseenMessages.includes(msg.connectionId)) { - contactsWithUnseenMessages.push(msg.connectionId) - messagesToShow.push(msg) - } - }) - const proofsDone = useProofByState([ProofState.Done, ProofState.PresentationReceived]).filter( - (proof: ProofExchangeRecord) => { - if (proof.isVerified === undefined) return false - const metadata = proof.metadata.get(ProofMetadata.customMetadata) as ProofCustomMetadata - return !metadata?.details_seen - } - ) + const credsReceived = useCredentialByState(CredentialState.CredentialReceived) + const credsDone = useCredentialByState(CredentialState.Done) + const proofsDone = useProofByState([ProofState.Done, ProofState.PresentationReceived]) useEffect(() => { - const getNonAttestationProofs = async () => { - const nonAttestationProofs = ( - await Promise.all( - [...proofsRequested, ...proofsDone].map(async (proof: ProofExchangeRecord) => { - const isAttestation = await isProofRequestingAttestation( - proof, - agent as BifoldAgent, - AttestationRestrictions - ) - return { - value: proof, - include: !isAttestation, - } - }) - ) - ) - .filter((v) => v.include) - .map((data) => data.value) + // get all unseen messages + const unseenMessages: BasicMessageRecord[] = basicMessages.filter((msg) => { + const meta = msg.metadata.get(BasicMessageMetadata.customMetadata) as basicMessageCustomMetadata + return !meta?.seen + }) - setNonAttestationProofs(nonAttestationProofs) - } - getNonAttestationProofs() - }, [proofsRequested.length, proofsDone.length]) + // add one unseen message per contact to notifications + const contactsWithUnseenMessages: string[] = [] + const messagesToShow: BasicMessageRecord[] = [] + unseenMessages.forEach((msg) => { + if (!contactsWithUnseenMessages.includes(msg.connectionId)) { + contactsWithUnseenMessages.push(msg.connectionId) + messagesToShow.push(msg) + } + }) - const revoked = useCredentialByState(CredentialState.Done).filter((cred: CredentialRecord) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const metadata = cred!.metadata.get(CredentialMetadata.customMetadata) as credentialCustomMetadata - if (cred?.revocationNotification && metadata?.revoked_seen == undefined) { - return cred - } - }) + const revoked = credsDone.filter((cred: CredentialRecord) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const metadata = cred!.metadata.get(CredentialMetadata.customMetadata) as credentialCustomMetadata + if (cred?.revocationNotification && metadata?.revoked_seen == undefined) { + return cred + } + }) - const credentials = [ - ...useCredentialByState(CredentialState.CredentialReceived), - ...useCredentialByState(CredentialState.Done), - ] - const credentialDefinitionIDs = credentials.map( - (c) => c.metadata.data[AnonCredsCredentialMetadataKey].credentialDefinitionId as string - ) - const invitationDate = new Date() - const custom: CustomNotification[] = - showPersonCredentialSelector(credentialDefinitionIDs) && - !store.dismissPersonCredentialOffer.personCredentialOfferDismissed - ? [{ type: 'CustomNotification', createdAt: invitationDate, id: 'custom' }] - : [] + const credentials = [...credsDone, ...credsReceived] + const credentialDefinitionIDs = credentials.map( + (c) => c.metadata.data[AnonCredsCredentialMetadataKey].credentialDefinitionId as string + ) + const invitationDate = new Date() + const custom = + showPersonCredentialSelector(credentialDefinitionIDs) && + !store.dismissPersonCredentialOffer.personCredentialOfferDismissed + ? [{ type: 'CustomNotification', createdAt: invitationDate, id: 'custom' }] + : [] - let notifications: (BasicMessageRecord | CredentialRecord | ProofExchangeRecord | CustomNotification)[] = [ - ...messagesToShow, - ...offers, - ...nonAttestationProofs, - ...revoked, - ].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) + const notif = [...messagesToShow, ...offers, ...nonAttestationProofs, ...revoked].sort( + (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + ) - notifications = [...custom, ...notifications] + const notificationsWithCustom = [...custom, ...notif] + setNotifications(notificationsWithCustom as never[]) + }, [credsReceived, credsDone, basicMessages, nonAttestationProofs]) + + useEffect(() => { + const validProofsDone = proofsDone.filter((proof: ProofExchangeRecord) => { + if (proof.isVerified === undefined) return false + + const metadata = proof.metadata.get(ProofMetadata.customMetadata) as ProofCustomMetadata + return !metadata?.details_seen + }) + Promise.all( + [...proofsRequested, ...validProofsDone].map(async (proof: ProofExchangeRecord) => { + const isAttestation = await isProofRequestingAttestation(proof, agent as BifoldAgent, AttestationRestrictions) + return { + value: proof, + include: !isAttestation, + } + }) + ).then((val) => setNonAttestationProofs(val.filter((v) => v.include).map((data) => data.value))) + }, [proofsRequested, proofsDone]) - return { total: notifications.length, notifications } + return notifications } diff --git a/app/src/index.ts b/app/src/index.ts index ab8d69ff0..27082b7ab 100644 --- a/app/src/index.ts +++ b/app/src/index.ts @@ -15,7 +15,6 @@ import HomeFooterView from './components/HomeFooterView' import HomeHeaderView from './components/HomeHeaderView' import { AttestationRestrictions } from './constants' import { setup, activate, deactivate, status } from './helpers/PushNotificationsHelper' -import { useNotifications } from './hooks/notifications' import en from './localization/en' import fr from './localization/fr' import ptBr from './localization/pt-br' @@ -53,7 +52,6 @@ const configuration: ConfigurationContext = { enableTours: true, showPreface: true, disableOnboardingSkip: true, - useCustomNotifications: useNotifications, enablePushNotifications: { status: status, setup: setup, diff --git a/app/src/screens/PersonCredential.tsx b/app/src/screens/PersonCredential.tsx index 579686900..5e24576a8 100644 --- a/app/src/screens/PersonCredential.tsx +++ b/app/src/screens/PersonCredential.tsx @@ -1,6 +1,7 @@ import { useAgent } from '@credo-ts/react-hooks' -import { useStore, useTheme, Button, ButtonType, testIdWithKey, Stacks, Link } from '@hyperledger/aries-bifold-core' -import { useNavigation } from '@react-navigation/native' +import { useStore, useTheme, Button, ButtonType, testIdWithKey, Link } from '@hyperledger/aries-bifold-core' +import { NotificationStackParams, Screens } from '@hyperledger/aries-bifold-core/lib/typescript/App/types/navigators' +import { StackScreenProps } from '@react-navigation/stack' import React, { useState, useCallback, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { StyleSheet, Text, View, TouchableOpacity, Linking, Platform, ScrollView } from 'react-native' @@ -18,13 +19,14 @@ const links = { Help: 'https://www2.gov.bc.ca/gov/content/governments/government-id/person-credential#help', } as const -const PersonCredential: React.FC = () => { +type PersonProps = StackScreenProps + +const PersonCredential: React.FC = ({ navigation }) => { const { agent } = useAgent() const [store] = useStore() const [appInstalled, setAppInstalled] = useState(false) const { ColorPallet, TextTheme } = useTheme() const { t } = useTranslation() - const navigation = useNavigation() const styles = StyleSheet.create({ pageContainer: { @@ -102,9 +104,7 @@ const PersonCredential: React.FC = () => { return } - navigation.getParent()?.navigate(Stacks.NotificationStack, { - screen: 'PersonCredentialLoading', - }) + navigation.replace('PersonCredentialLoading' as never, {} as never) }, []) const getBCServicesCardApp = useCallback(() => { diff --git a/app/src/screens/PersonCredentialLoading.tsx b/app/src/screens/PersonCredentialLoading.tsx index 1024163a0..9bd8350a1 100644 --- a/app/src/screens/PersonCredentialLoading.tsx +++ b/app/src/screens/PersonCredentialLoading.tsx @@ -159,6 +159,7 @@ const PersonCredentialLoading: React.FC = () => { // user reasons or otherwise. if (!status) { setDidCompleteAttestationProofRequest(false) + navigation.goBack() } } diff --git a/app/src/services/attestation.ts b/app/src/services/attestation.ts index c1d22668c..304d08da1 100644 --- a/app/src/services/attestation.ts +++ b/app/src/services/attestation.ts @@ -93,7 +93,7 @@ type Restriction = { } const findCredDefIDs = (restrictions: [Restriction]): Array => { - return restrictions.map((rstr) => rstr.cred_def_id).filter((credDefId) => credDefId !== undefined) + return restrictions.map((rstr) => rstr.cred_def_id).filter((credDefId) => credDefId !== undefined) as string[] } const invitationUrlFromRestrictions = async ( @@ -110,12 +110,12 @@ const invitationUrlFromRestrictions = async ( } const pRestrictions = format.request?.[formatToUse]?.requested_attributes?.attestationInfo?.restrictions - const cred_def_ids = findCredDefIDs(pRestrictions as [any]) + const cred_def_ids = findCredDefIDs(pRestrictions as [Restriction]) for (const env in restrictions) { for (const credDefId of cred_def_ids) { - if ((restrictions as Record)[env].credDefIDs.includes(credDefId)) { - return (restrictions as Record)[env].invitationUrl + if (restrictions[env].credDefIDs.includes(credDefId)) { + return restrictions[env].invitationUrl } } } @@ -135,7 +135,7 @@ export const allCredDefIds = (restrictions: AttestationRestrictionsType): string const allCredDefIds: string[] = [] for (const env in restrictions) { - allCredDefIds.push(...(restrictions as Record)[env].credDefIDs) + allCredDefIds.push(...restrictions[env].credDefIDs) } return allCredDefIds diff --git a/yarn.lock b/yarn.lock index 671365857..b603ce587 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3021,9 +3021,9 @@ __metadata: languageName: node linkType: hard -"@hyperledger/aries-bifold-core@npm:1.0.0-alpha.292": - version: 1.0.0-alpha.292 - resolution: "@hyperledger/aries-bifold-core@npm:1.0.0-alpha.292" +"@hyperledger/aries-bifold-core@npm:1.0.0-alpha.295": + version: 1.0.0-alpha.295 + resolution: "@hyperledger/aries-bifold-core@npm:1.0.0-alpha.295" peerDependencies: "@credo-ts/anoncreds": 0.5.9 "@credo-ts/askar": 0.5.9 @@ -3097,13 +3097,13 @@ __metadata: uuid: ^9.0.0 bin: bifold: bin/bifold - checksum: 7f3aec9ea21aab6e7b74710ab510860e700edceb022ac7c74cf4b716935ecd40b4fbc7f501f98fbc793ffcfeb307c24007e66857b67a6bb99c0bcc03277a089a + checksum: 04733b502e997ad8b1b533c327059d321635070f1085b7047b791840f986f79860ec902d8067482d64d29ac352d2f4c055d354110a231efd01638acf6bb94633 languageName: node linkType: hard -"@hyperledger/aries-bifold-remote-logs@npm:1.0.0-alpha.292": - version: 1.0.0-alpha.292 - resolution: "@hyperledger/aries-bifold-remote-logs@npm:1.0.0-alpha.292" +"@hyperledger/aries-bifold-remote-logs@npm:1.0.0-alpha.295": + version: 1.0.0-alpha.295 + resolution: "@hyperledger/aries-bifold-remote-logs@npm:1.0.0-alpha.295" peerDependencies: "@credo-ts/core": 0.5.9 axios: ^1.4.0 @@ -3111,43 +3111,43 @@ __metadata: react: ^18.2.0 react-native: ^0.72.5 react-native-logs: ^5.1.0 - checksum: a4537bc054867d67b276fa2aa4ebf24cbc3042d675050b13b788eca06970a4f8657737f7466f8c09800bcf739a94c6b08b4c7b9a4dcd6fb2cd8eae7a3a3952ac + checksum: 28b2c8232e823dd6eedc7dd3a4684da1b67537757191fafe778ca5c679b466e79a48d45d76c451705c614e9428921a02fb92ead6ba5741ea6ed4dfd9d42811ff languageName: node linkType: hard -"@hyperledger/aries-bifold-verifier@npm:1.0.0-alpha.292": - version: 1.0.0-alpha.292 - resolution: "@hyperledger/aries-bifold-verifier@npm:1.0.0-alpha.292" +"@hyperledger/aries-bifold-verifier@npm:1.0.0-alpha.295": + version: 1.0.0-alpha.295 + resolution: "@hyperledger/aries-bifold-verifier@npm:1.0.0-alpha.295" peerDependencies: "@credo-ts/anoncreds": 0.5.9 "@credo-ts/core": 0.5.9 "@credo-ts/react-hooks": ^0.6.0 "@hyperledger/anoncreds-shared": 0.2.2 react: ^18.2.0 - checksum: bacbb7e4b14687493c3cf464dcce9f0267481a723a9f0f5bb2493271bd19c674450a91fa555b9c28f1020b8d838a74b0577ca3082988245eca40901f78700b89 + checksum: 30d312077446225906e22e3f3952628d279361898c7a6a5da9b627ee1a026af437a6803edcf7bc4017e0f1037f4f69fc72f61ef6bb5648bfb62f42ba0d4a0b40 languageName: node linkType: hard -"@hyperledger/aries-oca@npm:1.0.0-alpha.292": - version: 1.0.0-alpha.292 - resolution: "@hyperledger/aries-oca@npm:1.0.0-alpha.292" +"@hyperledger/aries-oca@npm:1.0.0-alpha.295": + version: 1.0.0-alpha.295 + resolution: "@hyperledger/aries-oca@npm:1.0.0-alpha.295" dependencies: "@credo-ts/anoncreds": "npm:0.5.9" "@credo-ts/core": "npm:0.5.9" axios: "npm:^1.4.0" lodash.startcase: "npm:^4.4.0" react-native-fs: "npm:^2.16.6" - checksum: 47f5b226339277e39484603404935a95958b7a347285c3f6cc7d14d6809f48f1f8b3c90fc61f38c19f08999edd7fb5ea26ae853c91d078d076bcf29229030290 + checksum: 12007cab1692deb99bede78fe6d52c41c7756af473184960040fc864dcc83f527480f73ffa3faba0891af97b93dd484823530289283f960a0ae3b343bb95fcbb languageName: node linkType: hard -"@hyperledger/aries-react-native-attestation@npm:1.0.0-alpha.292": - version: 1.0.0-alpha.292 - resolution: "@hyperledger/aries-react-native-attestation@npm:1.0.0-alpha.292" +"@hyperledger/aries-react-native-attestation@npm:1.0.0-alpha.295": + version: 1.0.0-alpha.295 + resolution: "@hyperledger/aries-react-native-attestation@npm:1.0.0-alpha.295" peerDependencies: react: "*" react-native: "*" - checksum: b945619db2f470eec1e9fee4078da35f53e6f299c517d765e8da33f291b0968bd05abd51d94a5bac9f207d475754f058f4532213440f9d8330883396ba79a889 + checksum: abeec4ec0e7631bae395963f581d76a2fc3ae453a260d2b40e1a82249d8953081c537732aee2e4d9c5c2df7c27932fb049d805d0245cf23d877811b5a0988f4e languageName: node linkType: hard @@ -7740,11 +7740,11 @@ __metadata: "@formatjs/intl-relativetimeformat": "npm:9.3.1" "@hyperledger/anoncreds-react-native": "npm:0.2.2" "@hyperledger/aries-askar-react-native": "npm:0.2.3" - "@hyperledger/aries-bifold-core": "npm:1.0.0-alpha.292" - "@hyperledger/aries-bifold-remote-logs": "npm:1.0.0-alpha.292" - "@hyperledger/aries-bifold-verifier": "npm:1.0.0-alpha.292" - "@hyperledger/aries-oca": "npm:1.0.0-alpha.292" - "@hyperledger/aries-react-native-attestation": "npm:1.0.0-alpha.292" + "@hyperledger/aries-bifold-core": "npm:1.0.0-alpha.295" + "@hyperledger/aries-bifold-remote-logs": "npm:1.0.0-alpha.295" + "@hyperledger/aries-bifold-verifier": "npm:1.0.0-alpha.295" + "@hyperledger/aries-oca": "npm:1.0.0-alpha.295" + "@hyperledger/aries-react-native-attestation": "npm:1.0.0-alpha.295" "@hyperledger/indy-vdr-react-native": "npm:0.2.2" "@hyperledger/indy-vdr-shared": "npm:0.2.2" "@react-native-async-storage/async-storage": "npm:1.15.11"