fix: tour -- close the save-bypass at its root, not by enumerating callers
Round 3's review found the enumeration approach (patchStore()'s blocked list) was still incomplete, and worse, live rather than dormant: keyboard shortcuts (Delete/Backspace/S) bypass the tour's click-blocking backdrop entirely, since CSS pointer-events does nothing to a window-level keydown listener. timeline.js's shortcut handler calls removeSelectedScenes(), removeAudioTrack(), removeSelectedOverlay(), and splitScene() -- none of them in the blocked list -- and every one ends in scheduleSave(), whose setTimeout calls the closure-scoped commit() directly, reaching a real, unmocked PUT /funpack/api/projects/<id>. tour-s1 is pre-selected from the moment the tour boots, so pressing Delete at any point immediately triggers this -- no click needed, no specific step required. The blocked-list pattern (three rounds of fixes: parsed.scenes crash, syncFromPreview, saveClipToMediaBin) was closing this one caller at a time and kept finding another. Fixed at the root instead: every mutating path in store.js funnels through the single closure-scoped commit() function before it can reach the network, so that's the one place a tour-mode guard covers every current AND future caller by construction, without needing tour.js to know the name of anything that might call it. Verified live: dispatched a real Delete keydown during the tour with tour-s1 selected (the default boot state) -- the scene still gets removed locally (harmless, it's fake demo data), but zero requests to /api/projects appear in the network log across the full debounce window after the fix, versus a real PUT before it. Confirmed the guard is a no-op outside tour mode (window.__FUNPACK_TOUR__ is false there) and the full 16-step tour sequence still completes with zero thrown errors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
da04063a77
commit
61a4817460
@@ -969,6 +969,17 @@
|
||||
}
|
||||
|
||||
async function commit(opts = {}) {
|
||||
// Every mutating path in this module funnels through here before it can
|
||||
// reach a real network write -- scheduleSave()'s own setTimeout calls
|
||||
// this closure-scoped function directly, so patching Store.commit (or
|
||||
// any individual caller) from outside cannot stop it. The tour's own
|
||||
// welcome copy promises "nothing here touches your real files," and
|
||||
// enumerating every caller in tour.js's blocklist misses ones reachable
|
||||
// outside a click (keyboard shortcuts bypass the tour's click-blocking
|
||||
// backdrop entirely, since CSS pointer-events does nothing to keydown
|
||||
// listeners) -- so the guard belongs here, once, covering every path by
|
||||
// construction instead of by an ever-growing enumeration.
|
||||
if (window.__FUNPACK_TOUR__) return;
|
||||
if (!state.project) return;
|
||||
if (_commitPromise) { _commitQueued = true; return _commitPromise; }
|
||||
const skipPreviewRefresh = !!opts.skipPreviewRefresh;
|
||||
|
||||
Reference in New Issue
Block a user