# SSR и гидрация (Snapshot)

Снимок (snapshot) позволяет сериализовать состояние кэша на сервере и передать его клиенту, чтобы избежать повторных запросов при гидрации. Механизм работает как для [ресурсов][resource], так и для [команд][command].


## getSnapshot()

Метод `api.getSnapshot()` собирает **только успешные** записи всех зарегистрированных ресурсов и возвращает объект `TApiSnapshot`:

```typescript
const snapshot = api.getSnapshot();
// → { version, keyPrefix, timestamp, resources: { ... } }
```

Каждая запись содержит `args`, `data` и `updatedAt`. Записи в состояниях pending, error и refreshing — пропускаются.


## initialSnapshot

На клиенте снимок передаётся в `createApi`:

```typescript
const api = createApi({
  initialSnapshot: snapshot,
});
```

Гидрация происходит **лениво**: при вызове `createResource()` библиотека ищет соответствующий slice в снимке и восстанавливает кэш-записи. После гидрации slice удаляется из внутреннего хранилища (consume-паттерн). Вызов `resetAll()` обнуляет сохранённый снимок целиком.

При загрузке проверяется `version` и `keyPrefix` — при несовпадении выбрасывается ошибка.


## snapshotValidTime

Опция `snapshotValidTime` определяет, сколько миллисекунд данные из снимка считаются актуальными. Доступна на уровне [API][api-readme] и на уровне отдельного ресурса (ресурс-уровень приоритетнее).

| Значение | Поведение |
|---|---|
| `false` (по умолчанию) | Данные из снимка считаются всегда валидными. |
| `number` (мс) | Если `Date.now() - updatedAt > snapshotValidTime`, запись автоматически инвалидируется после гидрации. |

Инвалидация запускает перезапрос — компонент получит свежие данные без дополнительного кода.

Опция ресурса `snapshotable: false` полностью исключает ресурс из механики снимков: он не сериализуется в `getSnapshot()` и не гидрируется из `initialSnapshot`. Используется для производных ресурсов, чьи данные принадлежат другому ресурсу (например, [проекционные ресурсы](./projection-resource.md) выставляют её автоматически).


## Жизненный цикл

1. **Сервер** — `api.getSnapshot()` сериализует успешные записи кэша в `TApiSnapshot`.
2. **Передача** — снимок передаётся клиенту как JSON (через `<script>`, props, cookie и т.д.).
3. **Создание API** — `createApi({ initialSnapshot })` валидирует версию и keyPrefix, сохраняет deep-клон.
4. **Гидрация ресурсов** — каждый `createResource()` достаёт свой slice и восстанавливает записи в [кэш][cache].
5. **Авто-инвалидация** — если задан `snapshotValidTime` и запись устарела, она инвалидируется с перезапросом.
6. **Consume** — использованный slice удаляется; `resetAll()` обнуляет снимок целиком.


## Что сериализуется

Каждая [успешная запись][cache] содержит три поля:

| Поле | Описание |
|---|---|
| `args` | Аргументы запроса |
| `data` | Данные ответа |
| `updatedAt` | Время последнего успешного ответа |

Версия снимка (`version`) проверяется при загрузке — при несовпадении гидрация невозможна.


## См. также

- [Кэш][cache] — управление кэш-записями и жизненный цикл GC
- [Машина состояний][machine] — восстановление из снимка через `Machine.fromSnapshot()`
- [API-справочник][api-readme] — таблица опций `initialSnapshot`, `snapshotValidTime`, `getSnapshot()`

---

[resource]: ./resource.md
[command]: ./command.md
[cache]: ../concepts/cache.md
[machine]: ../concepts/machine.md
[api-readme]: ../api/README.md
