Skip to content

fix(storage): 无法序列化的顶层值会成功覆盖有效 JSON 文件 #366

Open

Description

@gtdd123

问题

当前 main(9afa4604e71a008391622b13a5415c87a9721e90)的 packages/shared/src/storage/json-file-store.ts 在插值时直接使用 JSON.stringify(data, null, 2)。顶层 undefined、函数、Symbol,或 toJSON() 返回 undefined 的对象,序列化结果不是字符串,而是 undefined。

因此 write() 会成功 resolve,并用字面量 undefined\n 原子替换已有的有效 JSON;下一次读取才报 STORAGE_READ_FAILED。原子替换只能避免部分写入,不能避免发布这个无效结果。

复现

在仓库根目录使用 Bun 运行:

import { mkdtemp, readFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { JsonFileStore } from './packages/shared/src/storage/json-file-store.ts';

const root = await mkdtemp(join(tmpdir(), 'folio-json-repro-'));
try {
  const store = new JsonFileStore(root);
  await store.write('state.json', { kept: true });
  await store.write('state.json', undefined); // 当前错误地成功
  console.log(JSON.stringify(await readFile(join(root, 'state.json'), 'utf8')));
  await store.read('state.json', null);
} finally {
  await rm(root, { recursive: true, force: true });
}

实际输出文件内容:"undefined\n";随后 read 报 STORAGE_READ_FAILED。
环境:Windows x64,Bun 1.4.0(34cbb9a40)。

预期与修复范围

在创建目录/暂存文件之前检查序列化结果;无法形成 JSON 文本时,沿现有错误通道拒绝写入(STORAGE_WRITE_FAILED),保留最后一份有效文件。合法的 null、false、0、空字符串和自定义 toJSON 仍保持原行为。

这是公共存储 API 的输入边界缺陷;尚未证明当前正常 UI 操作会传入这些值,不声称已复现日常操作中的数据丢失。

我准备处理这个小范围修复,补充真实文件读写、重新打开 store、无暂存文件残留的回归测试。已核查开放 PR 全部标题和相关 open/closed issue/PR,未发现同题补丁;与 #351/#352 的筛选历史并发锁范围不同。

AI assistance:使用 Codex 辅助定位、编写回归测试与修复;上述现象已在未修改的存储实现上实际复现。

Activity

  1. gtdd123 commented on Oct 24, 2026

    @gtdd123
    Author

    /claim

  2. github-actions commented on Oct 24, 2026

    @github-actions

    @gtdd123 已认领该 Issue,并已自动设为 Assignee。提交 PR 时请在描述中写 Closes #366。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

claimedClaimed by a contributor and currently in progress

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions