# 保存与恢复

用 JSON 保存一份文档，理解存储位置、版本和恢复步骤。

Core 提供内容读写，存储位置由应用决定。先从“点击保存，把当前文档写到浏览器”开始，再增加恢复和版本检查。

## 保存当前内容

`editor.getJSON()` 返回节点、属性和格式。浏览器存储接收字符串，因此需要先序列化：

```ts [保存一份本地草稿]
const snapshot = { version: 1, content: editor.getJSON() }
localStorage.setItem('my-document', JSON.stringify(snapshot))
```

`version` 是应用自己的备份版本。以后修改节点结构时，可以识别需要迁移的数据。`localStorage` 只属于这个浏览器，不会自动跨设备同步，也不包含图片字节。

## 恢复时先检查内容

先读取并解析备份，检查版本，再用匹配的 Schema 验证内容。无已保存数据时才创建默认文档；文件损坏或版本不支持时保留原数据，让用户选择恢复方式。

下面的两个辅助函数演示显式保存和读取。`recipes/save.ts` 负责存储与基本版本检查，`recipes/types.ts` 定义备份结构；完整产品还需要按 Schema 验证节点和属性，见[文件操作](/build/files)。

### recipes/save.ts

```ts
import type { Editor, JSONContent } from "@quirekit/core";
import type { DocumentSnapshot } from "./types";

/**
 * Saves explicitly; storage failure propagates so callers cannot report false success.
 * @param editor - The current document authority.
 * @param storage - Host-selected browser or test storage.
 * @param key - Document-specific storage key.
 */
export function saveDocument(editor: Pick<Editor, "getJSON">, storage: Pick<Storage, "setItem">, key: string): void {
  const snapshot: DocumentSnapshot = { version: 1, content: editor.getJSON() };
  storage.setItem(key, JSON.stringify(snapshot));
}

/**
 * Reads the versioned envelope; the editor schema remains responsible for content admission.
 * @param storage - The same host storage used for saving.
 * @param key - Document-specific storage key.
 * @returns Saved canonical JSON, or null when this document has not been saved.
 */
export function readDocument(storage: Pick<Storage, "getItem">, key: string): JSONContent | null {
  const source = storage.getItem(key);
  if (source === null) return null;
  const value: unknown = JSON.parse(source);
  if (!value || typeof value !== "object" || !("version" in value) || value.version !== 1 || !("content" in value)) {
    throw new Error("Unsupported document snapshot version");
  }
  const content = value.content;
  if (!content || typeof content !== "object" || !("type" in content) || content.type !== "doc") {
    throw new Error("Invalid document snapshot");
  }
  return content as JSONContent;
}

```

### recipes/types.ts

```ts
import type { JSONContent } from "@quirekit/core";

/** Snapshot stored by this example host, not by the editor core. */
export interface DocumentSnapshot {
  /** Host-owned schema migration version. */ readonly version: 1;
  /** Canonical document from the active editor. */ readonly content: JSONContent;
}

```

## 什么时候显示保存成功

存储操作可能失败，需要捕获错误并显示重试入口。只有实际写入成功，才清除未保存提示。网络保存期间还可能继续输入，因此应确认完成的是哪一版内容，不能让旧请求清除新草稿的未保存状态。

自动保存可以监听内容变化，合并短时间内的请求；它仍需处理版本、失败和冲突。简单的“下载 JSON”只是生成备份文件，不等于已经接入刷新恢复或服务端同步。
