kingkont 0.20.5 → 0.20.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/renderer/board.js +6 -0
- package/renderer/media.js +28 -3
package/package.json
CHANGED
package/renderer/board.js
CHANGED
|
@@ -1572,6 +1572,12 @@ async function closeProject() {
|
|
|
1572
1572
|
catch (e) { console.warn(`[closeProject] ${label} failed:`, e?.message || e); }
|
|
1573
1573
|
};
|
|
1574
1574
|
|
|
1575
|
+
// КРИТИЧНО первым шагом: слить pending debounced save (см. media.js
|
|
1576
|
+
// scheduleSave). Без этого мутации только что отработавшего chat-тула
|
|
1577
|
+
// теряются — saveTimer ещё ждёт 300мс, а мы уже обнулили state.currentBoard.
|
|
1578
|
+
await safeAwait('flush pending save', async () => {
|
|
1579
|
+
if (typeof window.flushScheduledSave === 'function') await window.flushScheduledSave();
|
|
1580
|
+
});
|
|
1575
1581
|
safe('persist welcome flag', () => {
|
|
1576
1582
|
localStorage.setItem('welcomeOnNextStart', '1');
|
|
1577
1583
|
localStorage.setItem('lastLocation', 'welcome');
|
package/renderer/media.js
CHANGED
|
@@ -345,14 +345,23 @@ const _mediaHydrationObserver = new IntersectionObserver((entries) => {
|
|
|
345
345
|
}, { rootMargin: '400px' });
|
|
346
346
|
|
|
347
347
|
let saveTimer = null;
|
|
348
|
+
let _saveInFlight = null; // promise of currently-running save, или null
|
|
348
349
|
function scheduleSave() {
|
|
349
350
|
if (!state.currentBoard) return;
|
|
350
351
|
// Mark dirty чтобы external file-watcher (pollExternalChanges в board.js)
|
|
351
352
|
// знал что у нас есть pending изменения; reload без подтверждения не делаем.
|
|
352
353
|
state.currentBoard.dirty = true;
|
|
353
354
|
clearTimeout(saveTimer);
|
|
354
|
-
saveTimer = setTimeout(
|
|
355
|
-
|
|
355
|
+
saveTimer = setTimeout(() => { saveTimer = null; _runSaveNow(); }, 300);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Сериализуем последовательные save'ы (если предыдущий ещё в полёте — ждём
|
|
359
|
+
// его прежде чем запускать новый). Без этого два scheduleSave подряд могли
|
|
360
|
+
// бы конкурентно дёргать FSAH-handle.
|
|
361
|
+
async function _runSaveNow() {
|
|
362
|
+
if (_saveInFlight) { try { await _saveInFlight; } catch {} }
|
|
363
|
+
if (!state.currentBoard?.handle) return;
|
|
364
|
+
_saveInFlight = (async () => {
|
|
356
365
|
try {
|
|
357
366
|
const mtime = await saveBoardMetadata(state.currentBoard.handle, state.currentBoard.metadata);
|
|
358
367
|
// Обновляем lastDiskMtime — иначе pollExternalChanges подумает что это
|
|
@@ -362,8 +371,24 @@ function scheduleSave() {
|
|
|
362
371
|
}
|
|
363
372
|
if (state.currentBoard) state.currentBoard.dirty = false;
|
|
364
373
|
} catch (e) { console.error('save failed', e); }
|
|
365
|
-
}
|
|
374
|
+
})();
|
|
375
|
+
try { await _saveInFlight; } finally { _saveInFlight = null; }
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Принудительно слить pending debounced save (и дождаться уже идущего).
|
|
379
|
+
// Нужно перед closeProject — иначе тулы чата, которые только что
|
|
380
|
+
// scheduleSave'нули, теряют изменения когда state.currentBoard обнуляется
|
|
381
|
+
// до того как 300мс-таймер сработает.
|
|
382
|
+
async function flushScheduledSave() {
|
|
383
|
+
if (saveTimer) {
|
|
384
|
+
clearTimeout(saveTimer);
|
|
385
|
+
saveTimer = null;
|
|
386
|
+
await _runSaveNow();
|
|
387
|
+
} else if (_saveInFlight) {
|
|
388
|
+
try { await _saveInFlight; } catch {}
|
|
389
|
+
}
|
|
366
390
|
}
|
|
391
|
+
window.flushScheduledSave = flushScheduledSave;
|
|
367
392
|
|
|
368
393
|
async function refreshNodeDOM(nodeId) {
|
|
369
394
|
if (!state.currentBoard) return;
|