zebra-spaces: defer transcribe-restore past script-eval to avoid TDZ chain

Fox 2026-06-05: "1:34:48 PM JS unhandled: can't access lexical
declaration 'whisperWorker' before initialization."

The button-binding restore block ran synchronously at script eval
time, BEFORE the rest of the file's let/const declarations had been
initialized. transcribeEnabled and TRANSCRIBE_KEY got hoisted earlier
in the previous fix, but the restore body itself reaches further
down — into whisperWorker, listenerAudioNodes, audioCtx, micStream,
and a chain of helper functions whose bodies access more `let`s. Any
of those is enough to throw.

Wrap the whole restore in setTimeout(fn, 0). The current synchronous
script finishes (all decls initialized), then the queued task runs.
Now ensureWhisperWorker, startCaptureForUuid, startSelfCapture etc.
all see fully-initialized state.

Also added a try/catch around the block so any remaining edge-case
error gets logged instead of bubbling to window.onerror.
This commit is contained in:
Russell Ballestrini 2026-06-05 13:35:36 -04:00
parent 8086627086
commit 9345975c58
No known key found for this signature in database

View file

@ -1637,23 +1637,24 @@ try { if (localStorage.getItem(TRANSCRIBE_KEY) === '1') transcribeEnabled = true
$('btn-vault').addEventListener('click', () => $('vault-panel').classList.toggle('hidden'));
$('btn-transcribe').addEventListener('click', () => toggleTranscribe().catch(e => logLine('err','transcribe toggle: '+e.message)));
/* If transcribe was on at the previous session, restore the state
* now (UI label, transcript-log visibility, worker pre-warm).
* Captures attach lazily as remote speakers arrive and self capture
* fires when micStream is available — both paths already check the
* transcribeEnabled flag. */
/* If transcribe was on at the previous session, restore the state.
* Deferred via setTimeout so the rest of the script (including
* whisperWorker, listenerAudioNodes, audioCtx, micStream and the
* Whisper helper functions further down) has finished initializing
* — otherwise the restore body trips TDZ on those `let`/`const`s.
* Fox 2026-06-05: "can't access lexical declaration 'whisperWorker'
* before initialization." */
if (transcribeEnabled){
/* call setTranscribe with the SAME value but force-apply UI + spin
* the worker. The function's "same-state" branch refreshes UI and
* returns without flipping the flag. */
setTimeout(() => {
try {
applyTranscribeUI();
ensureWhisperWorker();
/* If captures need to be installed (e.g. listenerAudioNodes
* populated before this code ran), kick them off. */
for (const [uuid] of listenerAudioNodes){
startCaptureForUuid(uuid).catch(()=>{});
}
startSelfCapture().catch(()=>{});
} catch(e){ logLine('err', 'transcribe restore: '+e.message); }
}, 0);
}
/* log out — destructive: wipes Ed25519 + handle from localStorage and
@ -7426,8 +7427,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-05</span><br>
md5 <span class="stamp-md5">9870220482eb18365ec4f5c8f556d976</span><br>
sha256 <span class="stamp-sha">853b11dcfc8b3612fbe452d53df6cec037a125654ff858f79d891855f6396fad</span><br>
md5 <span class="stamp-md5">2735b0ba85cac127a1dee3bdc5ecd88e</span><br>
sha256 <span class="stamp-sha">725573c39710827dda977eb9dbcf13d05fad6cc73ba694448d3886f63810bd80</span><br>
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
</footer>