mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
0f535d0b80
* fix(notes): protect title IME, surface persist failures, harden paste Note titles rewrote controlled value during CJK composition (Sogou Wubi). Notes localStorage writes ignored QuotaExceededError so restarts lost content. Markdown paste intercept could preventDefault with a no-op insert (fixes #2783). Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(notes): commit title draft on blur for IME composition IME-only title entry never called onCommit until compositionend; blur could flush an empty draftTitle and then adopt the stale external value. Commit the local draft on blur before parent flushNoteDraft. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(notes): stash IME title drafts in refs without controlled rewrite Composition updates now live-stash into draftTitleRef for teardown and note-switch flushes, while onCommit still waits for idle IME. Blur syncs superseded external titles before flush so stale drafts cannot overwrite. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(notes): clear stashed title when IME composition is superseded compositionEnd now live-stashes the adopted external title so pagehide and note-switch flushes cannot persist rejected composed text. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(notes): cancel draft flush during IME title stash Prior idle commits could still debounce-flush mid-composition and rewrite the controlled title. Stash now clears the timer, and external supersede in the adopt effect live-stashes the authoritative title. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(notes): dedupe quota failure toasts during autosave Debounced draft flushes can hit QuotaExceededError repeatedly; rate-limit the error toast so users are not spammed every 300ms. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { STORAGE_KEY_NOTES } from "../../infrastructure/config/storageKeys.ts";
|
|
import { commitVaultNotesWrite } from "./vaultNotesPersistence.ts";
|
|
|
|
test("commitVaultNotesWrite reports failure when the storage write returns false", () => {
|
|
const writes: Array<{ key: string; value: unknown }> = [];
|
|
const result = commitVaultNotesWrite({
|
|
data: [{
|
|
id: "note-1",
|
|
title: "Draft",
|
|
content: "body",
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
}],
|
|
write: (key, value) => {
|
|
writes.push({ key, value });
|
|
return false;
|
|
},
|
|
});
|
|
|
|
assert.equal(result.persisted, false);
|
|
assert.equal(writes.length, 1);
|
|
assert.equal(writes[0]?.key, STORAGE_KEY_NOTES);
|
|
assert.equal(result.notes[0]?.title, "Draft");
|
|
});
|
|
|
|
test("commitVaultNotesWrite returns persisted notes when the write succeeds", () => {
|
|
const result = commitVaultNotesWrite({
|
|
data: [{
|
|
id: "note-1",
|
|
title: "Saved",
|
|
content: "ok",
|
|
createdAt: 1,
|
|
updatedAt: 2,
|
|
}],
|
|
write: () => true,
|
|
});
|
|
|
|
assert.equal(result.persisted, true);
|
|
assert.equal(result.notes[0]?.title, "Saved");
|
|
});
|
|
|
|
test("useVaultState updateNotes surfaces storage write failures", () => {
|
|
const source = readFileSync(new URL("./useVaultState.ts", import.meta.url), "utf8");
|
|
|
|
assert.match(source, /commitVaultNotesWrite/);
|
|
assert.match(source, /notify\.error/);
|
|
assert.match(source, /!persisted|persisted === false/);
|
|
assert.match(source, /return false/);
|
|
assert.match(source, /notesPersistFailureNotifiedAtRef/);
|
|
assert.match(source, /10_000/);
|
|
});
|