@@ -73,13 +73,27 @@ export default function Pins() {
7373 checkEncryptionKey ( ) ;
7474 } , [ user ] ) ;
7575
76+ // Timeout for download operations (5 minutes)
77+ const DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1000 ;
78+
7679 // Download and decrypt a pin with provided key bytes (used after setup)
7780 const downloadDecryptedWithKey = async ( pin : Pin , keyBytes : Uint8Array ) => {
7881 console . log ( '[Decryption] downloadDecryptedWithKey called for pin:' , pin . cid ) ;
7982
8083 setDecryptingPins ( prev => new Set ( prev ) . add ( pin . request_id ) ) ;
8184 setDecryptionError ( null ) ;
8285
86+ // Set timeout to auto-clear loading state in case of stuck operation
87+ const timeoutId = setTimeout ( ( ) => {
88+ console . warn ( '[Decryption] Download timeout reached, clearing loading state' ) ;
89+ setDecryptingPins ( prev => {
90+ const next = new Set ( prev ) ;
91+ next . delete ( pin . request_id ) ;
92+ return next ;
93+ } ) ;
94+ setDecryptionError ( 'Download timed out. Please try again.' ) ;
95+ } , DOWNLOAD_TIMEOUT_MS ) ;
96+
8397 try {
8498 const key = await importKey ( keyBytes ) ;
8599 console . log ( '[Decryption] Key imported, fetching and decrypting...' ) ;
@@ -110,6 +124,7 @@ export default function Pins() {
110124 setDecryptionError ( message ) ;
111125 }
112126 } finally {
127+ clearTimeout ( timeoutId ) ;
113128 setDecryptingPins ( prev => {
114129 const next = new Set ( prev ) ;
115130 next . delete ( pin . request_id ) ;
@@ -183,13 +198,30 @@ export default function Pins() {
183198 setDecryptingPins ( prev => new Set ( prev ) . add ( pin . request_id ) ) ;
184199 setDecryptionError ( null ) ;
185200
201+ // Set timeout to auto-clear loading state in case of stuck operation
202+ const timeoutId = setTimeout ( ( ) => {
203+ console . warn ( '[Decryption] Download timeout reached, clearing loading state' ) ;
204+ setDecryptingPins ( prev => {
205+ const next = new Set ( prev ) ;
206+ next . delete ( pin . request_id ) ;
207+ return next ;
208+ } ) ;
209+ setDecryptionError ( 'Download timed out. Please try again.' ) ;
210+ } , DOWNLOAD_TIMEOUT_MS ) ;
211+
186212 try {
187213 // Retrieve the stored key
188214 console . log ( '[Decryption] Retrieving stored key...' ) ;
189215 const keyBytes = await retrieveEncryptionKey ( user . email , user . email ) ;
190216 if ( ! keyBytes ) {
191217 console . log ( '[Decryption] No key found, showing setup modal' ) ;
218+ clearTimeout ( timeoutId ) ;
192219 setEncryptionKeyReady ( false ) ;
220+ setDecryptingPins ( prev => {
221+ const next = new Set ( prev ) ;
222+ next . delete ( pin . request_id ) ;
223+ return next ;
224+ } ) ;
193225 setShowSetupModal ( true ) ;
194226 return ;
195227 }
@@ -223,6 +255,7 @@ export default function Pins() {
223255 setDecryptionError ( message ) ;
224256 }
225257 } finally {
258+ clearTimeout ( timeoutId ) ;
226259 setDecryptingPins ( prev => {
227260 const next = new Set ( prev ) ;
228261 next . delete ( pin . request_id ) ;
0 commit comments