Skip to content

Commit d34ce43

Browse files
authored
feat: upgrade SelfClient foundation and expose MRZ parsing (#925)
* feat: expose MRZ parsing on client * feat: add SelfClient provider * feat: add react native entry * feat: add mobile sdk entry wrapper * upgrade packages * save wip * clean up tests to support new arch * abstract SelfMobileSdk * pr feedback * updates * pr updates * update lock * updates * fix types * updates * fix tests * test: verify provider memoization and add jsdoc (#929) * pr feedback
1 parent d4340ba commit d34ce43

27 files changed

+1382
-211
lines changed

docs/gigamind/pr-analysis-workflow.md

Lines changed: 129 additions & 171 deletions
Large diffs are not rendered by default.

docs/templates/pr-action-items-template.md

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,42 @@
11
<!--
22
INSTRUCTIONS FOR AGENTS:
3-
- Use giga_read_pr to fetch PR data and CodeRabbit comments
4-
- Focus on unresolved comments without '✅ Addressed' status
5-
- Group related issues by root cause (not just severity)
6-
- Include specific file paths and line numbers
7-
- Provide clear, actionable fixes
8-
- Add code examples for complex issues
9-
- Prioritize by "blocking merge" vs "architectural" vs "polish"
10-
- Create file as PR-{{NUMBER}}-ACTION-ITEMS.md in project root
3+
4+
CRITICAL FILTERING RULES - MUST FOLLOW EXACTLY:
5+
1. ONLY include comments that meet ALL criteria:
6+
✅ NO "✅ Addressed" status (must be truly unresolved)
7+
✅ NO "nitpick" or "suggestion" labels (medium+ severity only)
8+
✅ MEDIUM to CRITICAL impact (affects functionality, security, or architecture)
9+
✅ NOT cosmetic/style issues (unless security/performance related)
10+
✅ DO NOT include secrets, access tokens, API keys, private keys, MRZ data, or any PII. Redact sensitive values and replace with placeholders.
11+
12+
2. VERIFICATION PROCESS - MANDATORY:
13+
- Read EACH comment's status field carefully
14+
- Check for "✅ Addressed in commits X to Y" text
15+
- Verify comment type: "🛠️ Refactor suggestion", "⚠️ Potential issue", etc.
16+
- Exclude: style, formatting, naming, documentation-only suggestions
17+
- Include: security, memory leaks, breaking changes, API inconsistencies, platform compatibility
18+
19+
3. SEVERITY CLASSIFICATION:
20+
- CRITICAL: Security vulnerabilities, memory leaks, breaking platform compatibility
21+
- HIGH: API inconsistencies, type safety issues, significant architectural problems
22+
- MEDIUM: Test coverage gaps, minor architectural improvements, performance concerns
23+
- LOW/NITPICK: Style, naming, documentation, minor suggestions (EXCLUDE THESE)
24+
25+
4. DOUBLE-CHECK PROCESS:
26+
- After initial analysis, re-read ALL comments
27+
- Verify each "unresolved" issue is actually unresolved
28+
- Remove any that have been addressed in subsequent commits
29+
- If NO unresolved medium+ issues exist, state "All issues resolved ✅"
30+
- Run a final pass to ensure no credentials, secrets, or PII are present in examples, logs, or screenshots.
31+
32+
5. EXECUTION:
33+
- Use giga_read_pr to fetch PR data and CodeRabbit comments
34+
- Group related issues by root cause (not just severity)
35+
- Include specific file paths and line numbers from CodeRabbit metadata
36+
- Provide clear, actionable fixes with code examples
37+
- Prioritize by "blocking merge" vs "architectural" vs "polish"
38+
- Create file as PR-{{NUMBER}}-ACTION-ITEMS.md in project root
39+
- Follow gitignore pattern: PR-*-ACTION*.md
1140
-->
1241

1342
# PR {{PR_NUMBER}} Action Items
@@ -21,23 +50,52 @@ INSTRUCTIONS FOR AGENTS:
2150

2251
{{PR_SUMMARY}}
2352

53+
## Analysis Summary
54+
55+
<!-- IF ALL ISSUES RESOLVED, USE THIS SECTION: -->
56+
**After thorough review of all {{TOTAL_COMMENTS}} CodeRabbit comments, ALL issues have been resolved in subsequent commits. The PR is ready for merge.**
57+
58+
### Resolved Comments ✅ ({{TOTAL_COMMENTS}}/{{TOTAL_COMMENTS}})
59+
All comments show ✅ "Addressed" status, indicating they were fixed in commits:
60+
- {{RESOLVED_CATEGORY_1}} - Fixed in commits {{COMMIT_RANGE}}
61+
- {{RESOLVED_CATEGORY_2}} - Fixed in commits {{COMMIT_RANGE}}
62+
63+
### Unresolved Comments 🔴 (0/{{TOTAL_COMMENTS}})
64+
**None** - All comments have been addressed.
65+
66+
## Conclusion
67+
**This PR is ready for merge.** All CodeRabbit issues have been resolved.
68+
69+
<!-- IF UNRESOLVED ISSUES EXIST, USE SECTIONS BELOW INSTEAD: -->
70+
2471
## Critical Issues (Blocking Merge)
2572

73+
<!-- ONLY include if there are ACTUAL unresolved medium+ severity issues -->
74+
2675
### 1. {{ISSUE_TITLE}}
2776
**Files:** `{{FILE_PATH}}:{{LINE_NUMBER}}`
77+
**CodeRabbit Comment:** {{COMMENT_ID}}
2878
**Problem:** {{PROBLEM_DESCRIPTION}}
2979
**Fix:** {{SPECIFIC_FIX_OR_ACTION}}
3080

81+
**Code Example:**
82+
```{{LANGUAGE}}
83+
{{CODE_EXAMPLE}}
84+
```
85+
3186
### 2. {{ISSUE_TITLE}}
3287
**Files:** `{{FILE_PATH}}:{{LINE_NUMBER}}`
88+
**CodeRabbit Comment:** {{COMMENT_ID}}
3389
**Problem:** {{PROBLEM_DESCRIPTION}}
3490
**Fix:** {{SPECIFIC_FIX_OR_ACTION}}
3591

3692
## Required Actions
3793

3894
### Issue 1: {{GROUPED_ISSUE_TITLE}}
39-
**Files:** `{{FILE_PATH}}:{{LINE_NUMBER}}`, `{{FILE_PATH}}:{{LINE_NUMBER}}`
4095
**Root Cause:** {{ROOT_CAUSE_DESCRIPTION}}
96+
**Files Affected:**
97+
- `{{FILE_PATH}}:{{LINE_NUMBER}}` - {{ISSUE_DESCRIPTION}}
98+
- `{{FILE_PATH}}:{{LINE_NUMBER}}` - {{ISSUE_DESCRIPTION}}
4199

42100
**Actions:**
43101
- [ ] {{SPECIFIC_ACTION_1}}
@@ -50,13 +108,29 @@ INSTRUCTIONS FOR AGENTS:
50108
```
51109

52110
### Issue 2: {{GROUPED_ISSUE_TITLE}}
53-
**Files:** `{{FILE_PATH}}:{{LINE_NUMBER}}`
54111
**Root Cause:** {{ROOT_CAUSE_DESCRIPTION}}
112+
**Files Affected:**
113+
- `{{FILE_PATH}}:{{LINE_NUMBER}}` - {{ISSUE_DESCRIPTION}}
55114

56115
**Actions:**
57116
- [ ] {{SPECIFIC_ACTION_1}}
58117
- [ ] {{SPECIFIC_ACTION_2}}
59118

119+
## CodeRabbit Analysis Summary
120+
121+
### Resolved Comments ✅
122+
- {{RESOLVED_COMMENT_1}}
123+
- {{RESOLVED_COMMENT_2}}
124+
125+
### Unresolved Comments 🔴
126+
- {{UNRESOLVED_COMMENT_1}} - {{STATUS}}
127+
- {{UNRESOLVED_COMMENT_2}} - {{STATUS}}
128+
129+
### Comment Categories
130+
- **Critical:** {{COUNT}} comments (React Native compatibility, security, memory leaks)
131+
- **Architecture:** {{COUNT}} comments (API design, type safety)
132+
- **Code Quality:** {{COUNT}} comments (testing, imports, documentation)
133+
60134
## Testing Checklist
61135

62136
### Before Merge
@@ -101,4 +175,26 @@ INSTRUCTIONS FOR AGENTS:
101175

102176
---
103177

178+
## Agent Verification Checklist
179+
180+
**BEFORE FINALIZING - VERIFY EACH ITEM:**
181+
- [ ] ✅ Read ALL {{TOTAL_COMMENTS}} CodeRabbit comments thoroughly
182+
- [ ] ✅ Checked each comment for "✅ Addressed" status
183+
- [ ] ✅ Excluded all nitpick/style/documentation-only suggestions
184+
- [ ] ✅ Only included MEDIUM+ severity issues (security, architecture, functionality)
185+
- [ ] ✅ Verified unresolved count is accurate
186+
- [ ] ✅ If 0 unresolved issues, used "All issues resolved" template
187+
- [ ] ✅ Double-checked that each "unresolved" issue is actually unresolved
188+
189+
**SEVERITY VERIFICATION:**
190+
- [ ] ✅ CRITICAL: Security, memory leaks, platform compatibility ({{CRITICAL_COUNT}})
191+
- [ ] ✅ HIGH: API inconsistencies, type safety, architecture ({{HIGH_COUNT}})
192+
- [ ] ✅ MEDIUM: Test coverage, performance, minor architecture ({{MEDIUM_COUNT}})
193+
- [ ] ❌ LOW/NITPICK: Style, naming, docs (EXCLUDED - {{EXCLUDED_COUNT}})
194+
195+
---
196+
104197
**Last Updated:** {{DATE}}
198+
**CodeRabbit Comments Analyzed:** {{TOTAL_COMMENTS}}
199+
**Unresolved Medium+ Issues:** {{UNRESOLVED_COUNT}}
200+
**Excluded Low/Nitpick Issues:** {{EXCLUDED_COUNT}}

packages/mobile-sdk-alpha/package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@selfxyz/mobile-sdk-alpha",
3-
"version": "0.1.0",
3+
"version": "2.6.4",
44
"description": "Self SDK (alpha) for registering and proving. Adapters-first, RN-first with web shims.",
55
"keywords": [
66
"self",
@@ -14,7 +14,6 @@
1414
"exports": {
1515
".": {
1616
"types": "./dist/esm/index.d.ts",
17-
"react-native": "./dist/esm/index.js",
1817
"browser": "./dist/esm/browser.js",
1918
"import": "./dist/esm/index.js",
2019
"require": "./dist/cjs/index.cjs",
@@ -54,7 +53,15 @@
5453
"@selfxyz/common": "workspace:*",
5554
"tslib": "^2.6.2"
5655
},
56+
"peerDependencies": {
57+
"react": "^18.3.1",
58+
"react-native": "^0.75.4",
59+
"tamagui": "^1.126.0"
60+
},
5761
"devDependencies": {
62+
"@testing-library/react": "^14.1.2",
63+
"@types/react": "^18.3.4",
64+
"@types/react-dom": "^18.3.0",
5865
"@typescript-eslint/eslint-plugin": "^8.0.0",
5966
"@typescript-eslint/parser": "^8.0.0",
6067
"eslint": "^8.57.0",
@@ -63,7 +70,11 @@
6370
"eslint-plugin-prettier": "^5.5.4",
6471
"eslint-plugin-simple-import-sort": "^12.1.1",
6572
"eslint-plugin-sort-exports": "^0.8.0",
73+
"jsdom": "^24.0.0",
6674
"prettier": "^3.5.3",
75+
"react": "^18.3.1",
76+
"react-dom": "^18.3.1",
77+
"react-native": "0.75.4",
6778
"tsup": "^8.0.1",
6879
"typescript": "^5.9.2",
6980
"vitest": "^1.6.0"

packages/mobile-sdk-alpha/src/browser.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,15 @@ export type { QRProofOptions } from './qr';
3939
export type { SdkErrorCategory } from './errors';
4040

4141
export { SCANNER_ERROR_CODES, notImplemented, sdkError } from './errors';
42+
export { SelfClientContext, SelfClientProvider, useSelfClient } from './context';
43+
// Browser-only high-level component (DOM-based)
44+
export { SelfMobileSdk as SelfMobileSdkHighLevel } from './components/SelfMobileSdk';
45+
4246
export { createSelfClient } from './client';
47+
4348
export { defaultConfig } from './config/defaults';
49+
50+
/** @deprecated Use createSelfClient().extractMRZInfo or import from './mrz' */
4451
export { extractMRZInfo, formatDateToYYMMDD, scanMRZ } from './mrz';
4552

4653
// Core functions

packages/mobile-sdk-alpha/src/client.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { defaultConfig } from './config/defaults';
22
import { mergeConfig } from './config/merge';
33
import { notImplemented } from './errors';
4+
import { extractMRZInfo as parseMRZInfo } from './processing/mrz';
45
import type {
56
Adapters,
67
Config,
@@ -19,6 +20,11 @@ import type {
1920
ValidationResult,
2021
} from './types/public';
2122

23+
/**
24+
* Optional adapter implementations used when a consumer does not provide their
25+
* own. These defaults are intentionally minimal no-ops suitable for tests and
26+
* non-production environments.
27+
*/
2228
const optionalDefaults: Partial<Adapters> = {
2329
storage: {
2430
get: async () => null,
@@ -36,6 +42,13 @@ const optionalDefaults: Partial<Adapters> = {
3642
},
3743
};
3844

45+
/**
46+
* Creates a fully configured {@link SelfClient} instance.
47+
*
48+
* The function validates that all required adapters are supplied and merges the
49+
* provided configuration with sensible defaults. Missing optional adapters are
50+
* filled with benign no-op implementations.
51+
*/
3952
export function createSelfClient({ config, adapters }: { config: Config; adapters: Partial<Adapters> }): SelfClient {
4053
const cfg = mergeConfig(defaultConfig, config);
4154
const required: (keyof Adapters)[] = ['scanner', 'network', 'crypto'];
@@ -77,6 +90,10 @@ export function createSelfClient({ config, adapters }: { config: Config; adapter
7790
return { registered: false, reason: 'SELF_REG_STATUS_STUB' };
7891
}
7992

93+
async function registerDocument(_input: RegistrationInput): Promise<RegistrationStatus> {
94+
return { registered: false, reason: 'SELF_REG_STATUS_STUB' };
95+
}
96+
8097
async function generateProof(
8198
_req: ProofRequest,
8299
opts: {
@@ -101,7 +118,9 @@ export function createSelfClient({ config, adapters }: { config: Config; adapter
101118
scanDocument,
102119
validateDocument,
103120
checkRegistration,
121+
registerDocument,
104122
generateProof,
123+
extractMRZInfo: parseMRZInfo,
105124
on,
106125
emit,
107126
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { ComponentType, ReactNode } from 'react';
2+
3+
import { SelfClientProvider } from '../context';
4+
import { useDocumentManager } from '../hooks/useDocumentManager';
5+
import type { Adapters, Config } from '../types/public';
6+
import type { ExternalAdapter, PassportCameraProps, ScreenProps } from '../types/ui';
7+
import { OnboardingFlow } from './flows/OnboardingFlow';
8+
import { QRCodeScreen } from './screens/QRCodeScreen';
9+
10+
interface SelfMobileSdkProps {
11+
config: Config;
12+
adapters?: Partial<Adapters>;
13+
external: ExternalAdapter;
14+
children?: ReactNode;
15+
// Optional custom components
16+
customScreens?: {
17+
PassportCamera?: ComponentType<PassportCameraProps>;
18+
NFCScanner?: ComponentType<ScreenProps>;
19+
QRScanner?: ReactNode;
20+
};
21+
}
22+
23+
const SelfMobileSdkContent = ({
24+
external,
25+
customScreens = {},
26+
}: {
27+
external: ExternalAdapter;
28+
customScreens?: SelfMobileSdkProps['customScreens'];
29+
}) => {
30+
const { documents, isLoading, hasRegisteredDocuments } = useDocumentManager(external);
31+
32+
if (isLoading) {
33+
return <div>Loading documents...</div>;
34+
}
35+
36+
// Check if user has any registered documents
37+
const hasDocuments = Object.keys(documents).length > 0 && hasRegisteredDocuments();
38+
39+
if (!hasDocuments) {
40+
return (
41+
<OnboardingFlow
42+
external={external}
43+
setDocument={external.setDocument}
44+
PassportCamera={customScreens.PassportCamera}
45+
NFCScanner={customScreens.NFCScanner}
46+
/>
47+
);
48+
}
49+
50+
// Show disclosure flow
51+
return (
52+
customScreens.QRScanner || (
53+
<QRCodeScreen onSuccess={external.onDisclosureSuccess} onFailure={external.onDisclosureFailure} />
54+
)
55+
);
56+
};
57+
58+
export const SelfMobileSdk = ({ config, adapters = {}, external, children, customScreens }: SelfMobileSdkProps) => {
59+
return (
60+
<SelfClientProvider config={config} adapters={adapters}>
61+
{children || <SelfMobileSdkContent external={external} customScreens={customScreens} />}
62+
</SelfClientProvider>
63+
);
64+
};

0 commit comments

Comments
 (0)