An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(identity-wallet): address Phase 5 code review feedback

Critical fixes:
- extractPds: Access didDoc.services (object) instead of didDoc.service (array)
- isDeviceKeyRoot: Directly access didDoc.rotationKeys instead of iterating verificationMethod

Important fixes:
- Remove duplicate 'border: none' CSS property on .identity-card (conflicted with border: 1px solid)
- Remove unused HomeScreen import from +page.svelte

Minor fixes:
- Simplify getBadgeInfo to getBadgeLabel returning string instead of object with unused className
- Show identities without DID docs with fallback display (DID only) instead of silently omitting them

All issues verified with TypeScript/Svelte type checking (0 errors).

authored by

Malpercio and committed by
Tangled
4c413f14 3bc1245e

+26 -49
+26 -48
apps/identity-wallet/src/lib/components/home/IdentityListHome.svelte
··· 42 42 } 43 43 44 44 function extractPds(didDoc: Record<string, unknown>): string | null { 45 - const service = didDoc.service; 46 - if (!Array.isArray(service)) return null; 47 - for (const svc of service) { 48 - if (typeof svc === 'object' && svc !== null) { 49 - const id = svc.id; 50 - const type = svc.type; 51 - const endpoint = svc.serviceEndpoint; 52 - if ((id === '#atproto_pds' || type === 'AtprotoPersonalDataServer') && typeof endpoint === 'string') { 53 - return endpoint; 54 - } 55 - } 56 - } 57 - return null; 45 + const services = didDoc.services; 46 + if (typeof services !== 'object' || services === null) return null; 47 + const pds = (services as Record<string, unknown>).atproto_pds; 48 + if (typeof pds !== 'object' || pds === null) return null; 49 + const endpoint = (pds as Record<string, unknown>).endpoint; 50 + return typeof endpoint === 'string' ? endpoint : null; 58 51 } 59 52 60 53 function isDeviceKeyRoot( 61 54 didDoc: Record<string, unknown>, 62 55 deviceKeyId: string 63 56 ): boolean | null { 64 - const verificationMethod = didDoc.verificationMethod; 65 - if (!Array.isArray(verificationMethod)) return null; 66 - 67 - let rotationKeys: string[] = []; 68 - for (const vm of verificationMethod) { 69 - if (typeof vm === 'object' && vm !== null) { 70 - const id = vm.id; 71 - const type = vm.type; 72 - if (id === '#rotation' && type === 'Multikey') { 73 - const publicKeyMultibase = vm.publicKeyMultibase; 74 - if (typeof publicKeyMultibase === 'string') { 75 - rotationKeys.push(publicKeyMultibase); 76 - } 77 - } 78 - } 79 - } 80 - 81 - if (rotationKeys.length === 0) return null; 57 + const rotationKeys = didDoc.rotationKeys; 58 + if (!Array.isArray(rotationKeys) || rotationKeys.length === 0) return null; 82 59 return rotationKeys[0] === deviceKeyId; 83 60 } 84 61 ··· 96 73 getDeviceKeyId(did), 97 74 ]); 98 75 76 + // Show identity even if DID doc is missing (with fallback display) 77 + const handle = docResult ? extractHandle(docResult) : null; 78 + const pdsUrl = docResult ? extractPds(docResult) : null; 79 + const deviceKeyIsRoot = docResult ? isDeviceKeyRoot(docResult, keyIdResult) : null; 80 + 99 81 if (docResult) { 100 82 didDocs.set(did, docResult); 101 - const handle = extractHandle(docResult); 102 - const pdsUrl = extractPds(docResult); 103 - const deviceKeyIsRoot = isDeviceKeyRoot(docResult, keyIdResult); 83 + } 104 84 105 - identities.push({ 106 - did, 107 - handle, 108 - pdsUrl, 109 - deviceKeyIsRoot, 110 - }); 111 - } 85 + identities.push({ 86 + did, 87 + handle, 88 + pdsUrl, 89 + deviceKeyIsRoot, 90 + }); 112 91 } catch (e) { 113 92 console.error(`Failed to load identity ${did}:`, e); 114 93 } ··· 126 105 loadData(); 127 106 }); 128 107 129 - function getBadgeInfo(deviceKeyIsRoot: boolean | null): { label: string; className: string } { 108 + function getBadgeLabel(deviceKeyIsRoot: boolean | null): string { 130 109 if (deviceKeyIsRoot === true) { 131 - return { label: 'Root Key', className: 'badge--root' }; 110 + return 'Root Key'; 132 111 } else if (deviceKeyIsRoot === false) { 133 - return { label: 'Not Root', className: 'badge--not-root' }; 112 + return 'Not Root'; 134 113 } 135 - return { label: 'Unknown', className: 'badge--unknown' }; 114 + return 'Unknown'; 136 115 } 137 116 </script> 138 117 ··· 158 137 {#each identities as card (card.did)} 159 138 <button 160 139 class="identity-card" 161 - onclick={() => onselect(card.did, didDocs.get(card.did)!)} 140 + onclick={() => onselect(card.did, didDocs.get(card.did) ?? {})} 162 141 > 163 142 <div class="card-content"> 164 143 <DIDAvatar did={card.did} handle={card.handle ?? 'Unknown'} /> ··· 179 158 class:badge--unknown={card.deviceKeyIsRoot === null} 180 159 > 181 160 <span class="badge-dot"></span> 182 - {getBadgeInfo(card.deviceKeyIsRoot).label} 161 + {getBadgeLabel(card.deviceKeyIsRoot)} 183 162 </span> 184 163 {/if} 185 164 </div> ··· 266 245 justify-content: space-between; 267 246 gap: 1rem; 268 247 cursor: pointer; 269 - border: none; 270 248 width: 100%; 271 249 text-align: left; 272 250 transition: background 0.2s, border-color 0.2s;
-1
apps/identity-wallet/src/routes/+page.svelte
··· 19 19 import EmailVerificationScreen from '$lib/components/onboarding/EmailVerificationScreen.svelte'; 20 20 import ReviewOperationScreen from '$lib/components/onboarding/ReviewOperationScreen.svelte'; 21 21 import ClaimSuccessScreen from '$lib/components/onboarding/ClaimSuccessScreen.svelte'; 22 - import HomeScreen from '$lib/components/home/HomeScreen.svelte'; 23 22 import DIDDocumentScreen from '$lib/components/home/DIDDocumentScreen.svelte'; 24 23 import RecoveryInfoScreen from '$lib/components/home/RecoveryInfoScreen.svelte'; 25 24 import { createAccount, listIdentities, type CreateAccountError, type OAuthError, type HomeData, type IdentityInfo, type VerifiedClaimOp, type ClaimResult } from '$lib/ipc';