Skip to content

Conversation

@transphorm
Copy link
Member

@transphorm transphorm commented Oct 2, 2025

Summary

  • replace the demo client's stubbed WebSocket adapter with a real implementation backed by the global WebSocket
  • add minimal abort handling and event wiring so proving flows can complete in the demo

Testing

  • not run

https://chatgpt.com/codex/tasks/task_b_68ddbbe00fc0832dbe576278874aea78

Summary by CodeRabbit

  • New Features

    • Extract and display document holder names; added name-based display in lists and registration.
    • “Clear All Documents” action with confirmation and progress.
    • New modal picker components for simpler selection; headers now support a right-side action.
    • Registration timestamps added; documents now sort with registered items first.
    • Registration flow supports a one-shot completion callback.
  • Bug Fixes

    • More robust MRZ parsing, including single-line TD1 and broader TD3 prefixes.
  • Chores

    • Dependency updates and cleanup; pinned an iOS pod to a specific commit.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

Walkthrough

Adds registeredAt to DocumentMetadata, implements extractNameFromDocument, updates MRZ parsing for TD1/TD3 and name extraction, exports new utility, enhances demo app: new picker components, header rightAction, documents hook (sorting, clearAll), registration hook one-shot completion, documents list and register screen logic/UI updates, WebSocket adapter overhaul, demo dependencies and Podfile tweak.

Changes

Cohort / File(s) Summary
Types: Document metadata
common/src/utils/types.ts, packages/mobile-sdk-alpha/src/types/ui.ts
Add optional field registeredAt?: number to DocumentMetadata.
Mobile SDK Alpha: documents utilities and exports
packages/mobile-sdk-alpha/src/documents/utils.ts, packages/mobile-sdk-alpha/src/index.ts
New extractNameFromDocument(selfClient, documentId); update registration state to set/clear registeredAt; export extractNameFromDocument from index (duplicate export line noted).
Mobile SDK Alpha: MRZ processing
packages/mobile-sdk-alpha/src/processing/mrz.ts
Handle single-line TD1 by splitting into 3x30; extend TD3 name regex to allow I/P/O; keep existing parsing.
Demo components: pickers
packages/mobile-sdk-demo/src/components/SimplePicker.tsx, .../PickerField.tsx, .../AlgorithmCountryFields.tsx
Introduce modal SimplePicker; add PickerField wrapper; add AlgorithmCountryFields composing two PickerFields.
Demo layout: header
packages/mobile-sdk-demo/src/components/StandardHeader.tsx, .../ScreenLayout.tsx
Add optional rightAction prop; layout top row with back and optional action; pass through from ScreenLayout to StandardHeader.
Demo hooks: documents and registration
packages/mobile-sdk-demo/src/hooks/useDocuments.ts, .../useRegistration.ts
useDocuments: sorting by registration, clearing state/action clearAllDocuments with rollback. useRegistration: add one-shot completion callback setOnComplete; invoke on event and completed state; reset clears callback.
Demo provider: WebSocket and key
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx
WebSocket adapter uses global WebSocket, supports AbortSignal and headers; normalize message events; error when unavailable; getPrivateKey ensures 0x prefix.
Demo screens: documents and registration
packages/mobile-sdk-demo/src/screens/DocumentsList.tsx, .../RegisterDocument.tsx, .../GenerateMock.tsx, .../index.ts
DocumentsList: load/display extracted names; add Clear All with confirmation and header action. RegisterDocument: use extractNameFromDocument; auto-select first available; PickerField; onComplete handler via hook. GenerateMock: refactor to new picker components; UX timing; conditional navigation/alerts. screens/index: pass refreshDocuments as onSuccess to Register screen.
Demo configuration
packages/mobile-sdk-demo/package.json, packages/mobile-sdk-demo/ios/Podfile
Remove @react-native-picker/picker; pin react-native-svg to 15.12.1 (no caret); pin NFCPassportReader pod to specific commit.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor UI as Screen
  participant SDK as mobile-sdk-alpha
  participant Client as SelfClient
  participant Store as DocumentStore

  UI->>SDK: extractNameFromDocument(selfClient, documentId)
  SDK->>Client: loadDocument(documentId)
  Client->>Store: get document
  Store-->>Client: document
  Client-->>SDK: document
  alt Aadhaar
    SDK->>SDK: parse extractedFields.name
    SDK-->>UI: { firstName, lastName }
  else MRZ
    SDK->>SDK: extractNameFromMRZ(document.mrz)
    SDK-->>UI: { firstName, lastName } or null
  else Other/invalid
    SDK-->>UI: null
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Hook as useDocuments
  participant Catalog as CatalogProvider
  participant Storage as DocumentStorage

  User->>Hook: clearAllDocuments()
  Hook->>Catalog: snapshot catalog
  Hook->>Catalog: clear catalog (optimistic)
  par delete files
    Hook->>Storage: delete all document blobs
  and delete meta
    Hook->>Storage: remove metadata entries
  end
  alt deletion ok
    Hook->>Hook: refresh()
    Hook-->>User: done
  else deletion fails
    Hook->>Catalog: rollback to snapshot
    Hook-->>User: error
  end
Loading
sequenceDiagram
  autonumber
  actor App
  participant Adapter as WsAdapter
  participant WS as WebSocket

  App->>Adapter: connect(url, {signal, headers})
  alt WebSocket available
    Adapter->>WS: new WebSocket(url)
    Adapter->>Adapter: bind onmessage/onerror/onclose
    Adapter-->>App: WsConn { send, close, onMessage... }
    opt AbortSignal
      App->>Adapter: signal.abort
      Adapter->>WS: close()
    end
  else WebSocket missing
    Adapter-->>App: throw Error("Provide a WebSocket implementation")
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

New names from lines of MRZ flow,
Aadhaar whispers, TD1 in tow.
A header gains a subtle hand,
Clear-all sweeps like desert sand.
WebSockets speak, with signals set—
RegisteredAt marks when we met.
Ship it softly; all boxes checked.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The pull request title “Fix mobile demo app document registration” only refers to document registration fixes, but the changeset spans adding name extraction, registration timestamps, UI components, hook enhancements, and a real WebSocket adapter, making it too narrow and misleading. Update the title to succinctly reflect the broader scope, such as “Add document name extraction, registration timestamps, real WebSocket adapter, and UI enhancements to mobile demo.”
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run `@coderabbitai generate docstrings` to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit's high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-document-registration-issue

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@transphorm transphorm marked this pull request as ready for review October 2, 2025 19:48
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/mobile-sdk-alpha/src/processing/mrz.ts (1)

65-71: Remove MRZ logging immediately.

console.log('validateTD1Format', lines); dumps raw MRZ lines, exposing passports/IDs in logs. That’s a direct PII leak and violates our “never log sensitive data” rule. Drop the log (or fully anonymize/redact before logging) before shipping.

🧹 Nitpick comments (2)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (1)

57-75: Reduce type assertions and improve type safety.

The heavy use of any type assertions in the event attachment logic weakens type safety and could mask runtime type errors. The addEventListener checks could also be simplified.

Consider refactoring to:

-      const attach = (event: 'message' | 'error' | 'close', handler: (payload?: any) => void) => {
-        if (typeof socket.addEventListener === 'function') {
-          if (event === 'message') {
-            (socket.addEventListener as any)('message', handler as any);
-          } else if (event === 'error') {
-            (socket.addEventListener as any)('error', handler as any);
-          } else {
-            (socket.addEventListener as any)('close', handler as any);
-          }
-        } else {
-          if (event === 'message') {
-            (socket as any).onmessage = handler;
-          } else if (event === 'error') {
-            (socket as any).onerror = handler;
-          } else {
-            (socket as any).onclose = handler;
-          }
-        }
-      };
+      const attach = (event: 'message' | 'error' | 'close', handler: (e: any) => void) => {
+        if ('addEventListener' in socket && typeof socket.addEventListener === 'function') {
+          socket.addEventListener(event, handler);
+        } else {
+          // Fallback to onX properties
+          socket[`on${event}` as 'onmessage' | 'onerror' | 'onclose'] = handler;
+        }
+      };
packages/mobile-sdk-alpha/src/documents/utils.ts (1)

59-73: Consider edge cases in name splitting logic.

The space-based splitting for Aadhaar names handles 1-2 parts but may not handle:

  • Names with multiple spaces (e.g., " FIRST LAST ")
  • Single-word names correctly (currently returns empty lastName)
  • Titles or honorifics (e.g., "Mr. FIRST LAST")

Improve robustness:

       const name = document.extractedFields?.name;
       if (name && typeof name === 'string') {
         // Aadhaar name is typically "FIRSTNAME LASTNAME" format
-        const parts = name.trim().split(/\s+/);
+        const cleanName = name.trim().replace(/\s+/g, ' '); // normalize spaces
+        const parts = cleanName.split(' ');
         if (parts.length >= 2) {
           const firstName = parts[0];
           const lastName = parts.slice(1).join(' ');
           return { firstName, lastName };
-        } else if (parts.length === 1) {
-          return { firstName: parts[0], lastName: '' };
+        } else if (parts.length === 1 && parts[0]) {
+          // For single-name case, treat as lastName (common in India)
+          return { firstName: '', lastName: parts[0] };
         }
       }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1d30d1 and 53c3dcb.

⛔ Files ignored due to path filters (2)
  • packages/mobile-sdk-demo/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (17)
  • common/src/utils/types.ts (1 hunks)
  • packages/mobile-sdk-alpha/src/documents/utils.ts (3 hunks)
  • packages/mobile-sdk-alpha/src/index.ts (1 hunks)
  • packages/mobile-sdk-alpha/src/processing/mrz.ts (2 hunks)
  • packages/mobile-sdk-alpha/src/types/ui.ts (1 hunks)
  • packages/mobile-sdk-demo/package.json (1 hunks)
  • packages/mobile-sdk-demo/src/components/AlgorithmCountryFields.tsx (1 hunks)
  • packages/mobile-sdk-demo/src/components/PickerField.tsx (1 hunks)
  • packages/mobile-sdk-demo/src/components/ScreenLayout.tsx (1 hunks)
  • packages/mobile-sdk-demo/src/components/StandardHeader.tsx (2 hunks)
  • packages/mobile-sdk-demo/src/hooks/useDocuments.ts (2 hunks)
  • packages/mobile-sdk-demo/src/hooks/useRegistration.ts (4 hunks)
  • packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (2 hunks)
  • packages/mobile-sdk-demo/src/screens/DocumentsList.tsx (7 hunks)
  • packages/mobile-sdk-demo/src/screens/GenerateMock.tsx (6 hunks)
  • packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (8 hunks)
  • packages/mobile-sdk-demo/src/screens/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,ts,tsx,jsx,sol,nr}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{js,ts,tsx,jsx,sol,nr}: NEVER log sensitive data including PII (names, DOB, passport numbers, addresses), credentials, tokens, API keys, private keys, or session identifiers.
ALWAYS redact/mask sensitive fields in logs using consistent patterns (e.g., ***-***-1234 for passport numbers, J*** D*** for names).

Files:

  • common/src/utils/types.ts
  • packages/mobile-sdk-alpha/src/types/ui.ts
  • packages/mobile-sdk-demo/src/components/AlgorithmCountryFields.tsx
  • packages/mobile-sdk-demo/src/components/StandardHeader.tsx
  • packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx
  • packages/mobile-sdk-demo/src/components/ScreenLayout.tsx
  • packages/mobile-sdk-alpha/src/processing/mrz.ts
  • packages/mobile-sdk-demo/src/hooks/useRegistration.ts
  • packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx
  • packages/mobile-sdk-demo/src/screens/DocumentsList.tsx
  • packages/mobile-sdk-demo/src/screens/GenerateMock.tsx
  • packages/mobile-sdk-alpha/src/documents/utils.ts
  • packages/mobile-sdk-demo/src/components/PickerField.tsx
  • packages/mobile-sdk-demo/src/hooks/useDocuments.ts
  • packages/mobile-sdk-demo/src/screens/index.ts
  • packages/mobile-sdk-alpha/src/index.ts
common/src/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

common/src/**/*.{ts,tsx,js,jsx}: Review shared utilities for:

  • Reusability and modular design
  • Type safety and error handling
  • Side-effect management
  • Documentation and naming clarity

Files:

  • common/src/utils/types.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/mobile-sdk-alpha/AGENTS.md)

packages/mobile-sdk-alpha/**/*.{ts,tsx}: Use strict TypeScript type checking across the codebase
Follow ESLint TypeScript-specific rules
Avoid introducing circular dependencies

Files:

  • packages/mobile-sdk-alpha/src/types/ui.ts
  • packages/mobile-sdk-alpha/src/processing/mrz.ts
  • packages/mobile-sdk-alpha/src/documents/utils.ts
  • packages/mobile-sdk-alpha/src/index.ts
packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

packages/mobile-sdk-alpha/**/*.{ts,tsx,js,jsx}: Review alpha mobile SDK code for:

  • API consistency with core SDK
  • Platform-neutral abstractions
  • Performance considerations
  • Clear experimental notes or TODOs

Files:

  • packages/mobile-sdk-alpha/src/types/ui.ts
  • packages/mobile-sdk-alpha/src/processing/mrz.ts
  • packages/mobile-sdk-alpha/src/documents/utils.ts
  • packages/mobile-sdk-alpha/src/index.ts
packages/mobile-sdk-alpha/src/processing/**

📄 CodeRabbit inference engine (.cursor/rules/mobile-sdk-migration.mdc)

Place MRZ processing helpers in packages/mobile-sdk-alpha/src/processing/

Files:

  • packages/mobile-sdk-alpha/src/processing/mrz.ts
packages/mobile-sdk-alpha/src/index.ts

📄 CodeRabbit inference engine (.cursor/rules/mobile-sdk-migration.mdc)

Re-export new SDK modules via packages/mobile-sdk-alpha/src/index.ts

Files:

  • packages/mobile-sdk-alpha/src/index.ts
🧠 Learnings (3)
📚 Learning: 2025-08-29T15:31:15.924Z
Learnt from: CR
PR: selfxyz/self#0
File: packages/mobile-sdk-alpha/AGENTS.md:0-0
Timestamp: 2025-08-29T15:31:15.924Z
Learning: Applies to packages/mobile-sdk-alpha/{**/*.test.{ts,tsx},**/__tests__/**/*.{ts,tsx}} : Verify extractMRZInfo() using published sample MRZ strings (e.g., ICAO examples)

Applied to files:

  • packages/mobile-sdk-alpha/src/processing/mrz.ts
  • packages/mobile-sdk-alpha/src/index.ts
📚 Learning: 2025-08-24T18:54:04.809Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Applies to packages/mobile-sdk-alpha/src/processing/** : Place MRZ processing helpers in packages/mobile-sdk-alpha/src/processing/

Applied to files:

  • packages/mobile-sdk-alpha/src/processing/mrz.ts
📚 Learning: 2025-08-24T18:54:04.809Z
Learnt from: CR
PR: selfxyz/self#0
File: .cursor/rules/mobile-sdk-migration.mdc:0-0
Timestamp: 2025-08-24T18:54:04.809Z
Learning: Applies to packages/mobile-sdk-alpha/src/index.ts : Re-export new SDK modules via packages/mobile-sdk-alpha/src/index.ts

Applied to files:

  • packages/mobile-sdk-alpha/src/index.ts
🧬 Code graph analysis (7)
packages/mobile-sdk-demo/src/components/AlgorithmCountryFields.tsx (1)
packages/mobile-sdk-demo/src/components/PickerField.tsx (1)
  • PickerField (12-43)
packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (5)
app/src/providers/passportDataProvider.tsx (1)
  • setSelectedDocument (736-746)
packages/mobile-sdk-alpha/src/documents/utils.ts (1)
  • extractNameFromDocument (48-85)
packages/mobile-sdk-demo/src/components/ScreenLayout.tsx (1)
  • ScreenLayout (19-26)
packages/mobile-sdk-demo/src/utils/document.ts (1)
  • humanizeDocumentType (7-16)
packages/mobile-sdk-demo/src/components/LogsPanel.tsx (1)
  • LogsPanel (14-32)
packages/mobile-sdk-demo/src/components/ScreenLayout.tsx (2)
packages/mobile-sdk-demo/src/components/SafeAreaScrollView.tsx (1)
  • SafeAreaScrollView (13-27)
packages/mobile-sdk-demo/src/components/StandardHeader.tsx (1)
  • StandardHeader (15-28)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (2)
packages/mobile-sdk-alpha/src/types/public.ts (1)
  • WsConn (204-210)
packages/mobile-sdk-demo/src/utils/secureStorage.ts (1)
  • getOrCreateSecret (180-185)
packages/mobile-sdk-demo/src/screens/DocumentsList.tsx (4)
packages/mobile-sdk-demo/src/hooks/useDocuments.ts (1)
  • useDocuments (17-95)
packages/mobile-sdk-alpha/src/documents/utils.ts (1)
  • extractNameFromDocument (48-85)
packages/mobile-sdk-demo/src/utils/document.ts (1)
  • humanizeDocumentType (7-16)
packages/mobile-sdk-demo/src/components/ScreenLayout.tsx (1)
  • ScreenLayout (19-26)
packages/mobile-sdk-demo/src/screens/GenerateMock.tsx (1)
packages/mobile-sdk-demo/src/components/AlgorithmCountryFields.tsx (1)
  • AlgorithmCountryFields (13-46)
packages/mobile-sdk-alpha/src/documents/utils.ts (3)
packages/mobile-sdk-alpha/src/types/public.ts (1)
  • SelfClient (169-193)
common/src/utils/types.ts (2)
  • isAadhaarDocument (165-169)
  • isMRZDocument (171-177)
packages/mobile-sdk-alpha/src/processing/mrz.ts (1)
  • extractNameFromMRZ (254-326)
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-deps
  • GitHub Check: android-build-test
  • GitHub Check: e2e-ios
  • GitHub Check: analyze-ios
  • GitHub Check: analyze-android
🔇 Additional comments (10)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (1)

129-131: LGTM: 0x-prefix normalization is correct.

The addition of 0x-prefix normalization ensures compatibility with components expecting hex strings. The implementation is defensive and correct.

packages/mobile-sdk-alpha/src/types/ui.ts (1)

22-22: LGTM: registeredAt field addition is well-typed.

The optional registeredAt field with epoch ms semantics is correctly typed and documented. This aligns with the corresponding change in common/src/utils/types.ts.

packages/mobile-sdk-alpha/src/index.ts (1)

93-94: LGTM: Export follows SDK conventions.

The new extractNameFromDocument export is correctly placed with other document utilities and follows the established pattern for public API surface exposure.

Based on learnings.

common/src/utils/types.ts (1)

46-46: LGTM: registeredAt field maintains cross-package type consistency.

The addition of registeredAt?: number aligns with the parallel change in packages/mobile-sdk-alpha/src/types/ui.ts, ensuring consistent type definitions across the codebase.

packages/mobile-sdk-demo/src/screens/index.ts (1)

56-59: LGTM: refreshDocuments callback correctly wired.

The mapping of refreshDocuments to onSuccess provides clear semantics for post-registration refresh behavior and aligns with the broader refresh workflow improvements in this PR.

packages/mobile-sdk-alpha/src/documents/utils.ts (2)

271-277: LGTM: Timestamp management is correct.

The registeredAt timestamp is correctly set to Date.now() on registration and cleared on unregistration. This provides accurate tracking of registration state changes.


48-85: Verify Aadhaar name parsing assumptions. Splitting extractedFields.name on whitespace may not handle mononyms, multiple middle names, or compound surnames—add tests or expand parsing logic to cover these cases.

packages/mobile-sdk-demo/src/hooks/useDocuments.ts (1)

30-40: LGTM: Registration-based sorting improves UX.

Sorting registered documents first provides a better user experience by surfacing active/registered documents at the top of the list.

packages/mobile-sdk-demo/src/components/StandardHeader.tsx (2)

12-24: LGTM: rightAction prop correctly implemented.

The new rightAction prop is well-typed as React.ReactNode, properly positioned in a flex layout, and maintains backward compatibility as an optional prop.


34-39: LGTM: topRow layout is semantically correct.

The flexbox layout with space-between justification correctly positions the back button and right action at opposite ends while maintaining vertical alignment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (1)

44-44: Document the unused headers parameter.

The headers parameter in the connect signature is accepted but never used. WebSocket constructor in browsers doesn't support custom headers in the standard API (they must be set server-side or via subprotocols).

Either remove the unused parameter or document why it's present:

-    connect: (url: string, opts?: { signal?: AbortSignal; headers?: Record<string, string> }): WsConn => {
+    connect: (url: string, opts?: { signal?: AbortSignal; headers?: Record<string, string> /* Reserved for future use */ }): WsConn => {

Or if not needed in this environment, simplify:

-    connect: (url: string, opts?: { signal?: AbortSignal; headers?: Record<string, string> }): WsConn => {
+    connect: (url: string, opts?: { signal?: AbortSignal }): WsConn => {
🧹 Nitpick comments (1)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (1)

71-87: Consider type-safe event listener attachment.

Multiple as any type assertions could be avoided with proper typing. While functional, this reduces type safety and IntelliSense support.

Apply this diff to improve type safety:

-        if (typeof socket.addEventListener === 'function') {
-          if (event === 'message') {
-            (socket.addEventListener as any)('message', handler as any);
-          } else if (event === 'error') {
-            (socket.addEventListener as any)('error', handler as any);
-          } else {
-            (socket.addEventListener as any)('close', handler as any);
-          }
-        } else {
-          if (event === 'message') {
-            (socket as any).onmessage = handler;
-          } else if (event === 'error') {
-            (socket as any).onerror = handler;
-          } else {
-            (socket as any).onclose = handler;
-          }
-        }
+        if (typeof socket.addEventListener === 'function') {
+          socket.addEventListener(event, handler as EventListener);
+        } else {
+          const onEvent = `on${event}` as keyof typeof socket;
+          (socket[onEvent] as any) = handler;
+        }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53c3dcb and 73f92f8.

📒 Files selected for processing (4)
  • packages/mobile-sdk-demo/src/hooks/useDocuments.ts (3 hunks)
  • packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (2 hunks)
  • packages/mobile-sdk-demo/src/screens/DocumentsList.tsx (7 hunks)
  • packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (8 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,jsx,sol,nr}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{js,ts,tsx,jsx,sol,nr}: NEVER log sensitive data including PII (names, DOB, passport numbers, addresses), credentials, tokens, API keys, private keys, or session identifiers.
ALWAYS redact/mask sensitive fields in logs using consistent patterns (e.g., ***-***-1234 for passport numbers, J*** D*** for names).

Files:

  • packages/mobile-sdk-demo/src/hooks/useDocuments.ts
  • packages/mobile-sdk-demo/src/screens/DocumentsList.tsx
  • packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx
  • packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx
🧬 Code graph analysis (3)
packages/mobile-sdk-demo/src/screens/DocumentsList.tsx (4)
packages/mobile-sdk-demo/src/hooks/useDocuments.ts (1)
  • useDocuments (17-107)
packages/mobile-sdk-alpha/src/documents/utils.ts (1)
  • extractNameFromDocument (48-85)
packages/mobile-sdk-demo/src/utils/document.ts (1)
  • humanizeDocumentType (7-16)
packages/mobile-sdk-demo/src/components/ScreenLayout.tsx (1)
  • ScreenLayout (19-26)
packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (4)
app/src/providers/passportDataProvider.tsx (1)
  • setSelectedDocument (736-746)
packages/mobile-sdk-alpha/src/documents/utils.ts (1)
  • extractNameFromDocument (48-85)
packages/mobile-sdk-demo/src/utils/document.ts (1)
  • humanizeDocumentType (7-16)
packages/mobile-sdk-demo/src/components/LogsPanel.tsx (1)
  • LogsPanel (14-32)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (2)
packages/mobile-sdk-alpha/src/types/public.ts (1)
  • WsConn (204-210)
packages/mobile-sdk-demo/src/utils/secureStorage.ts (1)
  • getOrCreateSecret (180-185)
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build-deps
  • GitHub Check: e2e-ios
  • GitHub Check: analyze-android
  • GitHub Check: analyze-ios
🔇 Additional comments (30)
packages/mobile-sdk-demo/src/providers/SelfClientProvider.tsx (2)

61-68: LGTM! AbortSignal cleanup properly implemented.

The abort listener is now correctly removed when the socket closes, preventing the memory leak flagged in the previous review. The pattern wraps the close handler to ensure cleanup before invoking the original handler.


142-144: LGTM! Hex prefix normalization implemented correctly.

The 0x-prefix normalization ensures consistency for components expecting standard hex format. Error handling remains secure without exposing the private key.

packages/mobile-sdk-demo/src/hooks/useDocuments.ts (5)

7-7: LGTM on the import addition.

The DocumentCatalog type is correctly imported for use in the clearAllDocuments implementation.


23-23: LGTM on the clearing state.

The new clearing state is properly initialized and used to track the clearAllDocuments operation.


30-40: LGTM on the document sorting.

Sorting registered documents first provides a better UX by surfacing completed registrations at the top of the list.


69-104: LGTM on the atomic catalog clearing with rollback.

The implementation now properly addresses the race condition concern from the previous review:

  1. Reads and persists the original catalog first
  2. Atomically clears the catalog by writing an empty one
  3. Attempts deletions with proper rollback on failure
  4. Handles errors and loading states correctly

This ensures consistency between catalog and storage even if interrupted.


106-106: LGTM on the return statement update.

The hook's API is properly extended to include the new clearing state and clearAllDocuments action.

packages/mobile-sdk-demo/src/screens/DocumentsList.tsx (10)

5-5: LGTM on the import additions.

The necessary imports for the new name extraction and client access functionality are correctly added.

Also applies to: 9-9


25-27: LGTM on the hook additions.

The useSelfClient hook and new state/actions from useDocuments are properly integrated.


35-63: LGTM on the race condition fix.

The name loading effect now properly implements the cancellation pattern suggested in the previous review:

  1. Uses a cancelled flag to prevent stale state updates
  2. Uses Promise.all for concurrent fetching (more efficient than sequential)
  3. Clears documentNames when documents array is empty
  4. Returns a cleanup function that sets the cancellation flag

This eliminates the race condition where slower earlier runs could overwrite newer data.


65-80: LGTM on the clear all handler.

The confirmation dialog and error handling are implemented correctly. The handler properly awaits clearAllDocuments and shows user-friendly error messages.


121-124: LGTM on the updated empty state text.

The revised messaging is clearer and more helpful to users.


135-143: LGTM on the document name display.

The document header now properly shows the extracted full name when available, providing better UX.


171-171: LGTM on the memoization dependency update.

The documentNames dependency is correctly added to ensure the memoized content re-renders when names are loaded.


173-185: LGTM on the Clear All button.

The button properly:

  1. Shows a loading indicator when clearing
  2. Disables appropriately when clearing or no documents exist
  3. Uses consistent styling with the rest of the UI

188-188: LGTM on the ScreenLayout integration.

The Clear All button is properly passed as a rightAction to the header.


201-227: LGTM on the new styles.

The styles for the clear button, document name display, and disabled state are well-defined and consistent with the existing design system.

Also applies to: 250-264

packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (13)

6-6: LGTM on the import changes.

Platform import is needed for platform-specific styling, and the rename from extractNameFromMRZ to extractNameFromDocument aligns with the broader document type support.

Also applies to: 9-9


39-42: LGTM on the auto-selection initialization.

The selectedDocumentId now defaults to the newest unregistered document (via reverse()[0]) when no catalog selection exists, providing better UX.


47-47: LGTM on the documentNames state.

The state is properly typed and initialized for storing extracted names.


65-79: LGTM on the auto-selection effect.

The effect properly ensures that when no document is selected, it automatically selects the newest unregistered document, improving UX.


82-106: LGTM on the race condition fix.

The name loading effect now properly implements the cancellation pattern suggested in the previous review:

  1. Uses a cancelled flag to prevent stale state updates
  2. Uses Promise.all for concurrent fetching (more efficient)
  3. Filters to only load names for unregistered documents
  4. Returns a cleanup function that sets the cancellation flag

This eliminates the race condition where slower earlier runs could overwrite newer data.


131-152: LGTM on the one-shot completion handler.

The new completion flow:

  1. Properly uses setOnComplete to register a single handler
  2. Refreshes the catalog before showing success
  3. Shows a user-friendly success alert
  4. Cleans up by resetting selection and actions
  5. Cleans up the handler on unmount

This replaces the previous timeout-based approach with a more reliable event-driven pattern.


170-171: LGTM on the picker selection helpers.

The firstAvailableDocId and selectedIdForPicker helpers properly manage the picker's display state.


174-174: LGTM on the title update.

Removing the [WiP] suffix indicates the feature is now production-ready.


176-208: LGTM on the picker integration.

The picker:

  1. Conditionally renders only when documents are available
  2. Uses mode="dialog" for better mobile UX
  3. Properly integrates document names in the labels
  4. Shows a placeholder only when no documents are available
  5. Disables during registration

193-201: LGTM on the name integration in picker labels.

The label construction properly shows the full name when available, falling back to just document type and ID when names aren't loaded yet or unavailable.


222-222: LGTM on the LogsPanel update.

The props are correctly updated to use regState-based logs and showLogs.


226-226: LGTM on the conditional rendering updates.

The document section and empty state now properly check availableDocuments.length to avoid showing UI when no documents exist.

Also applies to: 253-259


289-289: LGTM on the platform-specific overflow handling.

The conditional overflow style prevents clipping issues on iOS while maintaining proper behavior on other platforms.

@transphorm transphorm changed the title Enable real WebSocket adapter in demo client Fix mobile demo app document registration Oct 3, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/mobile-sdk-demo/src/screens/GenerateMock.tsx (1)

63-134: Review the forced 500ms minimum loading delay for UX implications.

The artificial delay (lines 117-121) ensures a minimum loading display time, which can smooth perceived performance. However, this adds latency even when document generation is fast (<500ms).

Consider:

  • Is the UX improvement worth the guaranteed delay for fast operations?
  • Users on fast devices will experience unnecessary waiting
  • This pattern can accumulate delays if multiple operations occur in sequence

Alternative approach: only add delay if the operation was very fast (e.g., <100ms), which might indicate a cached or synchronous result that could appear jarring:

-      // Ensure minimum loading display time (500ms) for better UX
-      const elapsed = Date.now() - startTime;
-      if (elapsed < 500) {
-        await new Promise(resolve => setTimeout(resolve, 500 - elapsed));
-      }
+      // Smooth UX for very fast operations
+      const elapsed = Date.now() - startTime;
+      if (elapsed < 100) {
+        await new Promise(resolve => setTimeout(resolve, 100 - elapsed));
+      }
packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (2)

60-78: Consider consolidating the two auto-select effects.

There are two separate effects handling document selection (lines 60-68 and 71-78), both with similar logic. The first sets selection when none exists, the second resets when the current selection becomes unavailable.

These could be merged into a single effect to reduce redundancy and improve maintainability:

-  // Auto-select first available unregistered document (newest first)
-  useEffect(() => {
-    const availableDocuments = (catalog.documents || []).filter(doc => !doc.isRegistered).reverse();
-    const firstUnregisteredDocId = availableDocuments[0]?.id;
-
-    if (firstUnregisteredDocId && !selectedDocumentId) {
-      setSelectedDocumentId(firstUnregisteredDocId);
-    }
-  }, [catalog.documents, selectedDocumentId]);
-
-  // Auto-select when catalog changes and current selection is no longer available
-  useEffect(() => {
-    const availableDocuments = (catalog.documents || []).filter(doc => !doc.isRegistered).reverse();
-    const isCurrentSelectionAvailable = availableDocuments.some(doc => doc.id === selectedDocumentId);
-
-    if (!isCurrentSelectionAvailable && availableDocuments.length > 0) {
-      setSelectedDocumentId(availableDocuments[0].id);
-    }
-  }, [catalog.documents, selectedDocumentId]);
+  // Auto-select first available unregistered document
+  useEffect(() => {
+    const availableDocuments = (catalog.documents || []).filter(doc => !doc.isRegistered).reverse();
+    const firstUnregisteredDocId = availableDocuments[0]?.id;
+    const isCurrentSelectionAvailable = availableDocuments.some(doc => doc.id === selectedDocumentId);
+
+    // Select first doc if: no selection exists OR current selection is unavailable
+    if (firstUnregisteredDocId && (!selectedDocumentId || !isCurrentSelectionAvailable)) {
+      setSelectedDocumentId(firstUnregisteredDocId);
+    }
+  }, [catalog.documents, selectedDocumentId]);

129-151: Verify one-shot completion handler cleanup on unmount.

The effect sets actions.setOnComplete(...) and cleans up with actions.setOnComplete(null) on unmount (line 150). However, if the Alert is shown and the component unmounts before the user presses OK, the callbacks in lines 140-145 will still execute against unmounted state.

The mounted.current check on line 132 prevents the initial Alert, but the OK button callbacks (lines 141-144) could still run after unmount.

Consider adding the mounted check inside the OK button handler as well:

           {
             text: 'OK',
             onPress: () => {
-              if (mounted.current) {
+              if (mounted.current) {
                 setSelectedDocumentId('');
                 actions.reset();
               }
             },
           },

Alternatively, verify that the OK handler won't fire if the Alert is already dismissed by unmount.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73f92f8 and a54f0ac.

⛔ Files ignored due to path filters (2)
  • packages/mobile-sdk-demo/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • packages/mobile-sdk-demo/ios/Podfile (1 hunks)
  • packages/mobile-sdk-demo/package.json (1 hunks)
  • packages/mobile-sdk-demo/src/components/PickerField.tsx (1 hunks)
  • packages/mobile-sdk-demo/src/components/SimplePicker.tsx (1 hunks)
  • packages/mobile-sdk-demo/src/screens/GenerateMock.tsx (6 hunks)
  • packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/mobile-sdk-demo/src/components/PickerField.tsx
  • packages/mobile-sdk-demo/package.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,jsx,sol,nr}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{js,ts,tsx,jsx,sol,nr}: NEVER log sensitive data including PII (names, DOB, passport numbers, addresses), credentials, tokens, API keys, private keys, or session identifiers.
ALWAYS redact/mask sensitive fields in logs using consistent patterns (e.g., ***-***-1234 for passport numbers, J*** D*** for names).

Files:

  • packages/mobile-sdk-demo/src/components/SimplePicker.tsx
  • packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx
  • packages/mobile-sdk-demo/src/screens/GenerateMock.tsx
🧬 Code graph analysis (3)
packages/mobile-sdk-demo/src/components/SimplePicker.tsx (2)
packages/mobile-sdk-demo/src/components/PickerField.tsx (1)
  • PickerItem (10-10)
app/src/mocks/react-native-safe-area-context.js (1)
  • SafeAreaView (21-23)
packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (4)
app/src/providers/passportDataProvider.tsx (1)
  • setSelectedDocument (736-746)
packages/mobile-sdk-alpha/src/documents/utils.ts (1)
  • extractNameFromDocument (48-85)
packages/mobile-sdk-demo/src/components/PickerField.tsx (1)
  • PickerField (12-31)
packages/mobile-sdk-demo/src/utils/document.ts (1)
  • humanizeDocumentType (7-16)
packages/mobile-sdk-demo/src/screens/GenerateMock.tsx (2)
packages/mobile-sdk-demo/src/components/AlgorithmCountryFields.tsx (1)
  • AlgorithmCountryFields (13-46)
packages/mobile-sdk-demo/src/components/PickerField.tsx (1)
  • PickerField (12-31)
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-deps
  • GitHub Check: e2e-ios
  • GitHub Check: android-build-test
  • GitHub Check: analyze-android
  • GitHub Check: analyze-ios
🔇 Additional comments (5)
packages/mobile-sdk-demo/ios/Podfile (1)

29-29: Verify Podfile commit and repository access.

  • The GitHub API returned 404 for the fork/commit 9eff7c4e3a9037fdc1e03301584e0d5dcf14d76b; ensure the repo exists, is accessible, and the hash is correct.
  • Use HTTPS instead of SSH in CI/CD environments:
    pod "NFCPassportReader", git: "https://github.com/selfxyz/NFCPassportReader.git", commit: "9eff7c4e3a9037fdc1e03301584e0d5dcf14d76b"
  • Confirm NFC dependency updates belong in this PR versus a separate change.
packages/mobile-sdk-demo/src/components/SimplePicker.tsx (2)

18-35: LGTM! Clean picker implementation with proper disabled state handling.

The component correctly gates modal opening with the enabled prop and applies visual feedback via styles.disabled. The pressable interaction and chevron icon provide clear affordance.


37-60: Modal dismissal on Android back button is handled correctly.

The onRequestClose prop ensures the modal can be dismissed via Android's back button, which is a required behavior for Android modals. The modal animation and transparent background provide good UX.

packages/mobile-sdk-demo/src/screens/GenerateMock.tsx (1)

124-128: Verify first-document navigation logic aligns with user expectations.

The code auto-navigates to the register screen only when catalog.documents.length === 1. This means:

  • First document generated → auto-navigate to register
  • Subsequent documents → show success alert, stay on generate screen

Ensure this behavior matches the intended user flow. Users might expect to always be taken to registration or might prefer to stay on the generation screen to create multiple documents.

If the intent is to navigate only when the catalog was previously empty, the condition is correct. If users should always have the option to register immediately, consider adding a confirmation dialog with "Register Now" / "Stay Here" options.

packages/mobile-sdk-demo/src/screens/RegisterDocument.tsx (1)

80-105: LGTM! Cancellation flag properly prevents stale name updates.

The effect now includes a cancelled flag that gates the state update (line 95), addressing the race condition identified in the previous review. The parallel Promise.all approach (lines 86-94) is more efficient than sequential fetching.

Based on past review comments - the suggested fix has been correctly implemented.

@transphorm transphorm merged commit 318b83f into dev Oct 3, 2025
36 checks passed
@transphorm transphorm deleted the codex/fix-document-registration-issue branch October 3, 2025 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants