()
| 3217 | }; |
| 3218 | |
| 3219 | const loop = async () => { |
| 3220 | try { |
| 3221 | const st = await statusOnce(); |
| 3222 | const job = st?.job || null; |
| 3223 | latestJob = job; |
| 3224 | renderCryptoJobUi({ folder, mode, job }); |
| 3225 | |
| 3226 | if (!job || job.state === 'done') { |
| 3227 | finalizeCryptoJobUi({ folder, mode, jobId, ok: true }); |
| 3228 | return; |
| 3229 | } |
| 3230 | if (job.state === 'error') { |
| 3231 | finalizeCryptoJobUi({ folder, mode, jobId, ok: false, error: job.error }); |
| 3232 | return; |
| 3233 | } |
| 3234 | |
| 3235 | const tk = await tickWithHeartbeat(); |
| 3236 | const job2 = tk?.job || latestJob || job; |
| 3237 | latestJob = job2; |
| 3238 | renderCryptoJobUi({ folder, mode, job: job2 }); |
| 3239 | |
| 3240 | if (job2?.state === 'done') { |
| 3241 | finalizeCryptoJobUi({ folder, mode, jobId, ok: true }); |
| 3242 | return; |
| 3243 | } |
| 3244 | if (job2?.state === 'error') { |
| 3245 | finalizeCryptoJobUi({ folder, mode, jobId, ok: false, error: job2.error }); |
| 3246 | return; |
| 3247 | } |
| 3248 | } catch (e) { |
| 3249 | // transient errors: retry with backoff |
| 3250 | console.error('crypto job loop error', e); |
| 3251 | const status = Number(e?.status || 0); |
| 3252 | if (status === 401 || status === 403 || status === 404) { |
| 3253 | finalizeCryptoJobUi({ folder, mode, jobId, ok: false, error: e?.message || 'Crypto job failed.' }); |
| 3254 | return; |
| 3255 | } |
| 3256 | } |
| 3257 | |
| 3258 | __cryptoRunner = setTimeout(loop, 700); |
| 3259 | }; |
| 3260 | |
| 3261 | loop(); |
| 3262 | } |
no test coverage detected