···159159 // Verification options
160160 const [skipDuplicates, setSkipDuplicates] = useState(true);
161161162162+ const followsListUri = 'special:follows'; // Constant for the special URI
163163+162164 useEffect(() => {
163165 if (session) {
164166 const agentInstance = new Agent(session);
···449451 false // Not using direct fetch here
450452 );
451453 console.log(`Fetched ${lists.length} lists for user ${session.handle}`);
452452- setUserLists(lists || []);
454454+455455+ // Prepend the special "Follows" list
456456+ const followsPseudoList = {
457457+ uri: 'special:follows',
458458+ name: 'My Follows',
459459+ // We don't fetch the count here for performance, handle display in component
460460+ listItemCount: null // Indicate count is unknown/dynamic
461461+ };
462462+463463+ setUserLists([followsPseudoList, ...(lists || [])]); // Add follows list at the beginning
464464+453465 if (lists.length === 0) {
454454- setBulkVerifyStatus('You have not created any lists yet.');
466466+ // Adjust status message if only the pseudo-list exists
467467+ setBulkVerifyStatus('You have not created any custom lists yet.');
455468 } else {
456469 setBulkVerifyStatus(''); // Clear status on success if lists were found
457470 }
···704717 }
705718706719 setIsVerifying(true);
707707- setBulkVerifyStatus(`Fetching members of list: ${selectedList.name}...`);
720720+ setBulkVerifyStatus(`Fetching members of list: ${selectedList.name}...`); // Initial status
708721 setBulkVerifyProgress('');
709722 setStatusMessage(''); // Clear single verify status
710723 setRevokeStatusMessage(''); // Clear revoke status
711724725725+ // Initialize counters
712726 let successCount = 0;
713727 let failureCount = 0;
714728 let totalCount = 0;
715715- const errors = [];
729729+ let errors = [];
716730 let skippedCount = 0; // Track skipped users
717731718732 try {
719719- // Fetch all items from the selected list
720720- const listItems = await fetchAllPaginated(
721721- agent.api.app.bsky.graph, // The context object
722722- 'getList', // The method name as a string
723723- { list: selectedListUri, limit: 100 },
724724- false // Use agent method
725725- );
733733+ let fetchedItems = [];
734734+ let sourceDescription = selectedList ? `list "${selectedList.name}"` : "the selected list";
735735+ if (selectedListUri === followsListUri) {
736736+ sourceDescription = "follows list";
737737+ setBulkVerifyStatus(`Fetching your follows...`);
738738+ fetchedItems = await fetchAllPaginated(
739739+ agent.api.app.bsky.graph,
740740+ 'getFollows',
741741+ { actor: session.did, limit: 100 },
742742+ false
743743+ );
744744+ // The items are directly in the result array for getFollows
745745+ } else {
746746+ // Fetch items from a regular list
747747+ setBulkVerifyStatus(`Fetching members of list: ${selectedList.name}...`);
748748+ fetchedItems = await fetchAllPaginated(
749749+ agent.api.app.bsky.graph,
750750+ 'getList',
751751+ { list: selectedListUri, limit: 100 },
752752+ false
753753+ );
754754+ // For getList, the users are within the 'subject' property of each item
755755+ }
726756727727- totalCount = listItems.length;
728728- setBulkVerifyStatus(`Found ${totalCount} members in list "${selectedList.name}". Starting verification...`);
757757+ totalCount = fetchedItems.length;
758758+ setBulkVerifyStatus(`Found ${totalCount} members in ${sourceDescription}. Starting verification...`);
729759730760 if (totalCount === 0) {
731731- setBulkVerifyStatus(`List "${selectedList.name}" is empty. No users to verify.`);
761761+ setBulkVerifyStatus(`${sourceDescription} is empty. No users to verify.`);
732762 setIsVerifying(false);
733763 return;
734764 }
735765736766 // Iterate and verify each user
737737- for (let i = 0; i < listItems.length; i++) {
738738- const item = listItems[i];
739739- const targetUser = item.subject;
740740- const targetHandle = targetUser.handle;
741741- const targetDid = targetUser.did;
742742- const targetDisplayName = targetUser.displayName || targetHandle;
767767+ for (let i = 0; i < fetchedItems.length; i++) {
768768+ const item = fetchedItems[i];
769769+ let targetUser, targetHandle, targetDid, targetDisplayName;
770770+771771+ // Extract user details based on source
772772+ if (selectedListUri === followsListUri) {
773773+ // item is the user profile directly from getFollows result
774774+ targetUser = item;
775775+ targetDid = targetUser.did;
776776+ targetHandle = targetUser.handle;
777777+ targetDisplayName = targetUser.displayName || targetHandle;
778778+ } else {
779779+ // item is from getList result, user is in item.subject
780780+ targetUser = item.subject;
781781+ targetDid = targetUser.did;
782782+ targetHandle = targetUser.handle;
783783+ targetDisplayName = targetUser.displayName || targetHandle;
784784+ }
785785+786786+ // Check if essential details are present (safety check)
787787+ if (!targetDid || !targetHandle) {
788788+ console.warn(`Skipping item at index ${i} due to missing DID or handle`, item);
789789+ failureCount++;
790790+ errors.push(`Item ${i + 1}: Missing DID or handle`);
791791+ continue;
792792+ }
743793744794 setBulkVerifyProgress(`Verifying ${i + 1} of ${totalCount}: @${targetHandle}`);
745795···775825 }
776826777827 // Final status message
778778- let finalMessage = `Bulk verification complete for list "${selectedList.name}". \n`;
828828+ let finalMessage = `Bulk verification complete for ${sourceDescription}. \n`;
779829 finalMessage += `Successfully verified: ${successCount}. \n`;
780830 if (failureCount > 0) {
781831 finalMessage += `Failed: ${failureCount}. \n`;
···813863 return;
814864 }
815865866866+ // Determine source description early for use in error messages
867867+ let sourceDescription = selectedList ? `list "${selectedList.name}"` : "the selected list";
868868+ if (selectedListUriForRevoke === followsListUri) {
869869+ sourceDescription = "follows list";
870870+ }
871871+816872 // Confirmation dialog
817817- if (!window.confirm(`Are you sure you want to revoke verifications for all users found in the list "${selectedList.name}"? This cannot be undone.`)) {
873873+ if (!window.confirm(`Are you sure you want to revoke verifications for all users found in ${sourceDescription}? This cannot be undone.`)) {
818874 return;
819875 }
820876···826882 let successCount = 0;
827883 let failureCount = 0;
828884 let totalToRevoke = 0;
829829- const errors = [];
885885+ let errors = [];
830886831887 try {
832832- // Fetch all items from the selected list
833833- const listItems = await fetchAllPaginated(
834834- agent.api.app.bsky.graph,
835835- 'getList',
836836- { list: selectedListUriForRevoke, limit: 100 },
837837- false
838838- );
888888+ let fetchedItems = [];
889889+ let listMemberDids = new Set();
890890+ // sourceDescription is already set above
891891+892892+ // Check if it's the special Follows list
893893+ if (selectedListUriForRevoke === followsListUri) {
894894+ // sourceDescription = "follows list"; // Already set
895895+ setBulkRevokeStatus(`Fetching your follows...`);
896896+ fetchedItems = await fetchAllPaginated(
897897+ agent.api.app.bsky.graph,
898898+ 'getFollows',
899899+ { actor: session.did, limit: 100 },
900900+ false
901901+ );
902902+ // Extract DIDs directly from the follows list items
903903+ listMemberDids = new Set(fetchedItems.map(item => item.did));
904904+ } else {
905905+ // Fetch items from a regular list
906906+ setBulkRevokeStatus(`Fetching members of list: ${selectedList.name}...`);
907907+ fetchedItems = await fetchAllPaginated(
908908+ agent.api.app.bsky.graph,
909909+ 'getList',
910910+ { list: selectedListUriForRevoke, limit: 100 },
911911+ false
912912+ );
913913+ // Extract DIDs from the subject of list items
914914+ listMemberDids = new Set(fetchedItems.map(item => item.subject.did));
915915+ }
839916840840- if (listItems.length === 0) {
917917+ if (fetchedItems.length === 0 && selectedListUriForRevoke !== followsListUri) {
918918+ // Only show empty message if it wasn't the follows list (or if follows *was* empty)
841919 setBulkRevokeStatus(`List "${selectedList.name}" is empty. No users to check for revocation.`);
842920 setIsRevoking(false);
843921 return;
844922 }
845923846846- const listMemberDids = new Set(listItems.map(item => item.subject.did));
847847-848924 // Filter existing verifications to find those matching list members
849925 const verificationsToRevoke = verifications.filter(verification =>
850926 listMemberDids.has(verification.subject)
851927 );
852928853929 totalToRevoke = verificationsToRevoke.length;
854854- setBulkRevokeStatus(`Found ${totalToRevoke} existing verification(s) matching users in "${selectedList.name}". Starting revocation...`);
930930+ setBulkRevokeStatus(`Found ${totalToRevoke} existing verification(s) matching users in ${sourceDescription}. Starting revocation...`);
855931856932 if (totalToRevoke === 0) {
857857- setBulkRevokeStatus(`No existing verifications match users in the list "${selectedList.name}".`);
933933+ setBulkRevokeStatus(`No existing verifications match users in the ${sourceDescription}.`);
858934 setIsRevoking(false);
859935 return;
860936 }
···883959 }
884960885961 // Final status message
886886- let finalMessage = `Bulk revocation complete for list "${selectedList.name}". \n`;
962962+ let finalMessage = `Bulk revocation complete for ${sourceDescription}. \n`;
887963 finalMessage += `Successfully revoked: ${successCount}. \n`;
888964 if (failureCount > 0) {
889965 finalMessage += `Failed: ${failureCount}. \n`;
···895971 setSelectedListUriForRevoke(''); // Reset selection
896972897973 } catch (error) {
898898- console.error('Failed to fetch or process list items for revocation:', error);
899899- setBulkRevokeStatus(`Error during bulk revocation for "${selectedList.name}": ${error.message || 'Unknown error'}`);
974974+ console.error('Failed to fetch or process items for revocation:', error);
975975+ setBulkRevokeStatus(`Error during bulk revocation for ${sourceDescription}: ${error.message || 'Unknown error'}`);
900976 } finally {
901977 setIsRevoking(false);
902978 setBulkRevokeProgress('');
···9871063 onChange={(e) => setSkipDuplicates(e.target.checked)}
9881064 disabled={isVerifying}
9891065 />
990990- Skip Existing Verifications
10661066+ Prevent Duplications
9911067 </label>
9921068 </div>
9931069