@@ -45,7 +45,6 @@ import type { PropsWithChildren } from 'react';
4545import React , { createContext , useCallback , useContext , useMemo } from 'react' ;
4646import Keychain from 'react-native-keychain' ;
4747
48- import type { DocumentCategory , PassportData } from '@selfxyz/common/types' ;
4948import type {
5049 PublicKeyDetailsECDSA ,
5150 PublicKeyDetailsRSA ,
@@ -54,14 +53,26 @@ import {
5453 brutforceSignatureAlgorithmDsc ,
5554 parseCertificateSimple ,
5655} from '@selfxyz/common/utils' ;
56+ import type {
57+ DocumentCatalog ,
58+ DocumentCategory ,
59+ DocumentMetadata ,
60+ PassportData ,
61+ } from '@selfxyz/common/utils/types' ;
62+ import {
63+ DocumentsAdapter ,
64+ getAllDocuments ,
65+ SelfClient ,
66+ useSelfClient ,
67+ } from '@selfxyz/mobile-sdk-alpha' ;
5768
5869import { unsafe_getPrivateKey , useAuth } from '@/providers/authProvider' ;
5970
6071// Create safe wrapper functions to prevent undefined errors during early initialization
6172// These need to be declared early to avoid dependency issues
6273const safeLoadDocumentCatalog = async ( ) : Promise < DocumentCatalog > => {
6374 try {
64- return await loadDocumentCatalog ( ) ;
75+ return await loadDocumentCatalogDirectlyFromKeychain ( ) ;
6576 } catch ( error ) {
6677 console . warn (
6778 'Error in safeLoadDocumentCatalog, returning empty catalog:' ,
@@ -71,9 +82,9 @@ const safeLoadDocumentCatalog = async (): Promise<DocumentCatalog> => {
7182 }
7283} ;
7384
74- const safeGetAllDocuments = async ( ) => {
85+ const safeGetAllDocuments = async ( selfClient : SelfClient ) => {
7586 try {
76- return await getAllDocuments ( ) ;
87+ return await getAllDocuments ( selfClient ) ;
7788 } catch ( error ) {
7889 console . warn (
7990 'Error in safeGetAllDocuments, returning empty object:' ,
@@ -83,20 +94,6 @@ const safeGetAllDocuments = async () => {
8394 }
8495} ;
8596
86- export interface DocumentMetadata {
87- id : string ; // contentHash as ID for deduplication
88- documentType : string ; // passport, mock_passport, id_card, etc.
89- documentCategory : DocumentCategory ; // passport, id_card, aadhaar
90- data : string ; // DG1/MRZ data for passports/IDs, relevant data for aadhaar
91- mock : boolean ; // whether this is a mock document
92- isRegistered ?: boolean ; // whether the document is registered onChain
93- }
94-
95- export interface DocumentCatalog {
96- documents : DocumentMetadata [ ] ;
97- selectedDocumentId ?: string ; // This is now a contentHash
98- }
99-
10097type DocumentChangeCallback = ( isMock : boolean ) => void ;
10198
10299const documentChangeCallbacks : DocumentChangeCallback [ ] = [ ] ;
@@ -163,7 +160,7 @@ export const PassportContext = createContext<IPassportContext>({
163160 clearPassportData : clearPassportData ,
164161 clearSpecificData : clearSpecificPassportData ,
165162 loadDocumentCatalog : safeLoadDocumentCatalog ,
166- getAllDocuments : safeGetAllDocuments ,
163+ getAllDocuments : ( ) => Promise . resolve ( { } ) ,
167164 setSelectedDocument : setSelectedDocument ,
168165 deleteDocument : deleteDocument ,
169166 migrateFromLegacyStorage : migrateFromLegacyStorage ,
@@ -173,12 +170,12 @@ export const PassportContext = createContext<IPassportContext>({
173170 markCurrentDocumentAsRegistered : markCurrentDocumentAsRegistered ,
174171 updateDocumentRegistrationState : updateDocumentRegistrationState ,
175172 checkIfAnyDocumentsNeedMigration : checkIfAnyDocumentsNeedMigration ,
176- hasAnyValidRegisteredDocument : hasAnyValidRegisteredDocument ,
177173 checkAndUpdateRegistrationStates : checkAndUpdateRegistrationStates ,
178174} ) ;
179175
180176export const PassportProvider = ( { children } : PassportProviderProps ) => {
181177 const { _getSecurely } = useAuth ( ) ;
178+ const selfClient = useSelfClient ( ) ;
182179
183180 const getData = useCallback (
184181 ( ) => _getSecurely < PassportData > ( loadPassportData , str => JSON . parse ( str ) ) ,
@@ -192,7 +189,10 @@ export const PassportProvider = ({ children }: PassportProviderProps) => {
192189 ) ;
193190 } , [ _getSecurely ] ) ;
194191
195- const getAllData = useCallback ( ( ) => loadAllPassportData ( ) , [ ] ) ;
192+ const getAllData = useCallback (
193+ ( ) => loadAllPassportData ( selfClient ) ,
194+ [ selfClient ] ,
195+ ) ;
196196
197197 const getAvailableTypes = useCallback ( ( ) => getAvailableDocumentTypes ( ) , [ ] ) ;
198198
@@ -224,7 +224,7 @@ export const PassportProvider = ({ children }: PassportProviderProps) => {
224224 clearPassportData : clearPassportData ,
225225 clearSpecificData : clearSpecificPassportData ,
226226 loadDocumentCatalog : safeLoadDocumentCatalog ,
227- getAllDocuments : safeGetAllDocuments ,
227+ getAllDocuments : ( ) => safeGetAllDocuments ( selfClient ) ,
228228 setSelectedDocument : setSelectedDocument ,
229229 deleteDocument : deleteDocument ,
230230 migrateFromLegacyStorage : migrateFromLegacyStorage ,
@@ -234,7 +234,6 @@ export const PassportProvider = ({ children }: PassportProviderProps) => {
234234 markCurrentDocumentAsRegistered : markCurrentDocumentAsRegistered ,
235235 updateDocumentRegistrationState : updateDocumentRegistrationState ,
236236 checkIfAnyDocumentsNeedMigration : checkIfAnyDocumentsNeedMigration ,
237- hasAnyValidRegisteredDocument : hasAnyValidRegisteredDocument ,
238237 checkAndUpdateRegistrationStates : checkAndUpdateRegistrationStates ,
239238 } ) ,
240239 [
@@ -263,7 +262,7 @@ export async function checkAndUpdateRegistrationStates(): Promise<void> {
263262
264263export async function checkIfAnyDocumentsNeedMigration ( ) : Promise < boolean > {
265264 try {
266- const catalog = await loadDocumentCatalog ( ) ;
265+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
267266 return catalog . documents . some ( doc => doc . isRegistered === undefined ) ;
268267 } catch ( error ) {
269268 console . warn ( 'Error checking if documents need migration:' , error ) ;
@@ -273,7 +272,7 @@ export async function checkIfAnyDocumentsNeedMigration(): Promise<boolean> {
273272
274273export async function clearDocumentCatalogForMigrationTesting ( ) {
275274 console . log ( 'Clearing document catalog for migration testing...' ) ;
276- const catalog = await loadDocumentCatalog ( ) ;
275+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
277276
278277 // Delete all new-style documents
279278 for ( const doc of catalog . documents ) {
@@ -301,7 +300,7 @@ export async function clearDocumentCatalogForMigrationTesting() {
301300}
302301
303302export async function clearPassportData ( ) {
304- const catalog = await loadDocumentCatalog ( ) ;
303+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
305304
306305 // Delete all documents
307306 for ( const doc of catalog . documents ) {
@@ -317,7 +316,7 @@ export async function clearPassportData() {
317316}
318317
319318export async function clearSpecificPassportData ( documentType : string ) {
320- const catalog = await loadDocumentCatalog ( ) ;
319+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
321320 const docsToDelete = catalog . documents . filter (
322321 d => d . documentType === documentType ,
323322 ) ;
@@ -328,7 +327,7 @@ export async function clearSpecificPassportData(documentType: string) {
328327}
329328
330329export async function deleteDocument ( documentId : string ) : Promise < void > {
331- const catalog = await loadDocumentCatalog ( ) ;
330+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
332331
333332 // Remove from catalog
334333 catalog . documents = catalog . documents . filter ( d => d . id !== documentId ) ;
@@ -352,32 +351,14 @@ export async function deleteDocument(documentId: string): Promise<void> {
352351 }
353352}
354353
355- export async function getAllDocuments ( ) : Promise < {
356- [ documentId : string ] : { data : PassportData ; metadata : DocumentMetadata } ;
357- } > {
358- const catalog = await loadDocumentCatalog ( ) ;
359- const allDocs : {
360- [ documentId : string ] : { data : PassportData ; metadata : DocumentMetadata } ;
361- } = { } ;
362-
363- for ( const metadata of catalog . documents ) {
364- const data = await loadDocumentById ( metadata . id ) ;
365- if ( data ) {
366- allDocs [ metadata . id ] = { data, metadata } ;
367- }
368- }
369-
370- return allDocs ;
371- }
372-
373354export async function getAvailableDocumentTypes ( ) : Promise < string [ ] > {
374- const catalog = await loadDocumentCatalog ( ) ;
355+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
375356 return [ ...new Set ( catalog . documents . map ( d => d . documentType ) ) ] ;
376357}
377358
378359// Helper function to get current document type from catalog
379360export async function getCurrentDocumentType ( ) : Promise < string | null > {
380- const catalog = await loadDocumentCatalog ( ) ;
361+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
381362 if ( ! catalog . selectedDocumentId ) return null ;
382363
383364 const metadata = catalog . documents . find (
@@ -404,16 +385,6 @@ function getServiceNameForDocumentType(documentType: string): string {
404385 }
405386}
406387
407- export async function hasAnyValidRegisteredDocument ( ) : Promise < boolean > {
408- try {
409- const catalog = await loadDocumentCatalog ( ) ;
410- return catalog . documents . some ( doc => doc . isRegistered === true ) ;
411- } catch ( error ) {
412- console . error ( 'Error loading document catalog:' , error ) ;
413- return false ;
414- }
415- }
416-
417388/**
418389 * Global initialization function to wait for native modules to be ready
419390 * Call this once at app startup before any native module operations
@@ -460,10 +431,11 @@ export async function initializeNativeModules(
460431 return false ;
461432}
462433
463- export async function loadAllPassportData ( ) : Promise < {
434+ // TODO: is this used?
435+ async function loadAllPassportData ( selfClient : SelfClient ) : Promise < {
464436 [ service : string ] : PassportData ;
465437} > {
466- const allDocs = await getAllDocuments ( ) ;
438+ const allDocs = await getAllDocuments ( selfClient ) ;
467439 const result : { [ service : string ] : PassportData } = { } ;
468440
469441 // Convert to legacy format for backward compatibility
@@ -475,7 +447,7 @@ export async function loadAllPassportData(): Promise<{
475447 return result ;
476448}
477449
478- export async function loadDocumentById (
450+ export async function loadDocumentByIdDirectlyFromKeychain (
479451 documentId : string ,
480452) : Promise < PassportData | null > {
481453 try {
@@ -499,7 +471,12 @@ export async function loadDocumentById(
499471 return null ;
500472}
501473
502- export async function loadDocumentCatalog ( ) : Promise < DocumentCatalog > {
474+ export const selfClientDocumentsAdapter : DocumentsAdapter = {
475+ loadDocumentCatalog : loadDocumentCatalogDirectlyFromKeychain ,
476+ loadDocumentById : loadDocumentByIdDirectlyFromKeychain ,
477+ } ;
478+
479+ export async function loadDocumentCatalogDirectlyFromKeychain ( ) : Promise < DocumentCatalog > {
503480 try {
504481 // Extra safety check for module initialization
505482 if ( typeof Keychain === 'undefined' || ! Keychain ) {
@@ -524,6 +501,9 @@ export async function loadDocumentCatalog(): Promise<DocumentCatalog> {
524501 if ( parsed === null ) {
525502 throw new TypeError ( 'Cannot parse null password' ) ;
526503 }
504+
505+ console . log ( 'Successfully loaded document catalog from keychain' ) ;
506+
527507 return parsed ;
528508 }
529509 } catch ( error ) {
@@ -592,7 +572,7 @@ export async function loadSelectedDocument(): Promise<{
592572 data : PassportData ;
593573 metadata : DocumentMetadata ;
594574} | null > {
595- const catalog = await loadDocumentCatalog ( ) ;
575+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
596576 console . log ( 'Catalog loaded' ) ;
597577
598578 if ( ! catalog . selectedDocumentId ) {
@@ -618,7 +598,9 @@ export async function loadSelectedDocument(): Promise<{
618598 return null ;
619599 }
620600
621- const data = await loadDocumentById ( catalog . selectedDocumentId ) ;
601+ const data = await loadDocumentByIdDirectlyFromKeychain (
602+ catalog . selectedDocumentId ,
603+ ) ;
622604 if ( ! data ) {
623605 console . log ( 'Document data not found for id:' , catalog . selectedDocumentId ) ;
624606 return null ;
@@ -660,6 +642,7 @@ interface IPassportContext {
660642 signature : string ;
661643 data : PassportData ;
662644 } | null > ;
645+ // TODO: is this even used?
663646 getAllData : ( ) => Promise < { [ service : string ] : PassportData } > ;
664647 getAvailableTypes : ( ) => Promise < string [ ] > ;
665648 setData : ( data : PassportData ) => Promise < void > ;
@@ -673,12 +656,15 @@ interface IPassportContext {
673656 } | null > ;
674657 clearPassportData : ( ) => Promise < void > ;
675658 clearSpecificData : ( documentType : string ) => Promise < void > ;
659+
676660 loadDocumentCatalog : ( ) => Promise < DocumentCatalog > ;
677661 getAllDocuments : ( ) => Promise < {
678662 [ documentId : string ] : { data : PassportData ; metadata : DocumentMetadata } ;
679663 } > ;
664+
680665 setSelectedDocument : ( documentId : string ) => Promise < void > ;
681666 deleteDocument : ( documentId : string ) => Promise < void > ;
667+
682668 migrateFromLegacyStorage : ( ) => Promise < void > ;
683669 getCurrentDocumentType : ( ) => Promise < string | null > ;
684670 clearDocumentCatalogForMigrationTesting : ( ) => Promise < void > ;
@@ -688,12 +674,11 @@ interface IPassportContext {
688674 isRegistered : boolean ,
689675 ) => Promise < void > ;
690676 checkIfAnyDocumentsNeedMigration : ( ) => Promise < boolean > ;
691- hasAnyValidRegisteredDocument : ( ) => Promise < boolean > ;
692677 checkAndUpdateRegistrationStates : ( ) => Promise < void > ;
693678}
694679
695680export async function markCurrentDocumentAsRegistered ( ) : Promise < void > {
696- const catalog = await loadDocumentCatalog ( ) ;
681+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
697682 if ( catalog . selectedDocumentId ) {
698683 await updateDocumentRegistrationState ( catalog . selectedDocumentId , true ) ;
699684 } else {
@@ -703,7 +688,7 @@ export async function markCurrentDocumentAsRegistered(): Promise<void> {
703688
704689export async function migrateFromLegacyStorage ( ) : Promise < void > {
705690 console . log ( 'Migrating from legacy storage to new architecture...' ) ;
706- const catalog = await loadDocumentCatalog ( ) ;
691+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
707692
708693 // If catalog already has documents, skip migration
709694 if ( catalog . documents . length > 0 ) {
@@ -789,15 +774,15 @@ export async function saveDocumentCatalog(
789774}
790775
791776export async function setDefaultDocumentTypeIfNeeded ( ) {
792- const catalog = await loadDocumentCatalog ( ) ;
777+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
793778
794779 if ( ! catalog . selectedDocumentId && catalog . documents . length > 0 ) {
795780 await setSelectedDocument ( catalog . documents [ 0 ] . id ) ;
796781 }
797782}
798783
799784export async function setSelectedDocument ( documentId : string ) : Promise < void > {
800- const catalog = await loadDocumentCatalog ( ) ;
785+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
801786 const metadata = catalog . documents . find ( d => d . id === documentId ) ;
802787
803788 if ( metadata ) {
@@ -812,7 +797,7 @@ export async function storeDocumentWithDeduplication(
812797 passportData : PassportData ,
813798) : Promise < string > {
814799 const contentHash = calculateContentHash ( passportData ) ;
815- const catalog = await loadDocumentCatalog ( ) ;
800+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
816801
817802 // Check for existing document with same content
818803 const existing = catalog . documents . find ( d => d . id === contentHash ) ;
@@ -868,7 +853,7 @@ export async function updateDocumentRegistrationState(
868853 documentId : string ,
869854 isRegistered : boolean ,
870855) : Promise < void > {
871- const catalog = await loadDocumentCatalog ( ) ;
856+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
872857 const documentIndex = catalog . documents . findIndex ( d => d . id === documentId ) ;
873858
874859 if ( documentIndex !== - 1 ) {
@@ -885,3 +870,29 @@ export async function updateDocumentRegistrationState(
885870export const usePassport = ( ) => {
886871 return useContext ( PassportContext ) ;
887872} ;
873+
874+ /**
875+ * Get all documents directly from the keychain.
876+ *
877+ * It's here to avoid dependency on self client where it's not strictly necessary,
878+ * for example when migrating legacy data.
879+ *
880+ * @returns A dictionary of document IDs to their data and metadata.
881+ */
882+ export const getAllDocumentsDirectlyFromKeychain = async ( ) : Promise < {
883+ [ documentId : string ] : { data : PassportData ; metadata : DocumentMetadata } ;
884+ } > => {
885+ const catalog = await loadDocumentCatalogDirectlyFromKeychain ( ) ;
886+ const allDocs : {
887+ [ documentId : string ] : { data : PassportData ; metadata : DocumentMetadata } ;
888+ } = { } ;
889+
890+ for ( const metadata of catalog . documents ) {
891+ const data = await loadDocumentByIdDirectlyFromKeychain ( metadata . id ) ;
892+ if ( data ) {
893+ allDocs [ metadata . id ] = { data, metadata } ;
894+ }
895+ }
896+
897+ return allDocs ;
898+ } ;
0 commit comments