# @svelte-lean/query/persist

> persist() and indexedDbStore(): opt-in persistence per endpoint and per session, and the PersistStore contract.

Page: https://svelte-lean.vercel.app/query/api/persist · Markdown: https://svelte-lean.vercel.app/query/api/persist.md · Index: https://svelte-lean.vercel.app/llms.txt

persist(): opt-in persistence of endpoints marked persist, per session, restored lazily on first use and written behind; indexedDbStore() is the browser store.

> **Note** `./persist` is experimental: the API can still change in a minor release. Stability per entry point: [Entry points](https://svelte-lean.vercel.app/query.md#entry-points).

## Import

`import`

```ts
import { persist, indexedDbStore } from '@svelte-lean/query/persist';
```

## Usage

`src/lib/api/modules.ts`

```ts
// src/lib/api/modules.ts
import { defineQuery, type } from '@svelte-lean/query';
import { indexedDbStore, persist } from '@svelte-lean/query/persist';
import { session } from '$api/session.svelte';
import type { Team } from '$api/types';

export const storage = persist({
	store: indexedDbStore(),
	session: () => (session.userId === null ? null : String(session.userId)), // null: signed out
	buster: 'schema-3', // a new value drops every record
	maxAge: '24h'
});

// Only endpoints that opt in are stored.
export const listAllTeams = defineQuery({
	get: 'api/teams/all',
	result: type<Team[]>(),
	persist: true
});
```

## Size

Production Vite builds of a small consumer entry, Svelte external. A marginal row is the bytes the entry adds over the row it names.

| Build | Over | gzip | brotli | Budget (gzip) |
| --- | --- | --- | --- | --- |
| `persist (marginal)` | `query` | 3428 B | 3201 B | 3700 B |

Read from `packages/query/artifacts/size.json`. Every entry and its method: [Performance](https://svelte-lean.vercel.app/query/performance.md).

## Functions

The module and the IndexedDB store.

### Exports

Runtime exports of the entry.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `persist` | `(init: PersistInit) => PersistModule` | – | The module; only endpoints with persist are stored. |
| # `indexedDbStore` | `(init?: { name?: string }) => PersistStore` | `name 'slq'` | A PersistStore on IndexedDB. |

## Options

PersistInit, the argument of persist().

### PersistInit

store and session are required.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `store` required | `PersistStore` | – | Where records live. |
| # `session` required | `() => string \| null` | – | Reactive. The session the records belong to; null (signed out) reads and writes nothing. |
| # `buster` | `string` | – | Build or schema version; a different value drops every record. |
| # `maxAge` | `Duration` | `'24h'` | Record lifetime; an endpoint's persist.maxAge wins. |
| # `maxBytes` | `number` | `8 MiB` | Stored text per session partition; the oldest records are evicted first. |
| # `eager` | `QueryEndpoint[]` | – | Restored before ready resolves (at setup and on every session change). |
| # `compress` | `number \| false` | `262144` | gzip values longer than this many characters; false: never. |

### PersistModule

What persist() returns, beside the Module fields.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `ready` | `Promise<void>` | – | The eager restore is done (or timed out); never rejects. |
| # `forget` | `() => Promise<void>` | – | Delete this session's partition. |

## Store

The contract of a store; persistStoreSuite() in ./testing checks an implementation.

### PersistStore

Every method is asynchronous.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `get` | `(keys) => Promise<(PersistRecord \| undefined)[]>` | – | Read records by key. |
| # `put` | `(records) => Promise<void>` | – | Write each record unless the stored one has a newer updatedAt. |
| # `delete` | `(keys) => Promise<void>` | – | Delete records. |
| # `list` | `(prefix) => Promise<PersistMeta[]>` | – | Metadata of every key starting with prefix. |
| # `close` | `() => void` | – | Optional: close the store connection. |

### PersistMeta

A record without its value; PersistRecord adds value.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| # `key` | `string` | – | Session digest and entry key. |
| # `endpoint` | `string` | – | The endpoint id. |
| # `updatedAt` | `number` | – | Server commit time of the value. |
| # `writtenAt` | `number` | – | Time of the write (for maxAge and eviction). |
| # `bytes` | `number` | – | Length of the JSON text. |
| # `buster` | `string` | – | The buster the record was written with. |

## Guide

How to use it, with examples: [Persistence](https://svelte-lean.vercel.app/query/persistence.md). All entry points: [Svelte Lean Query](https://svelte-lean.vercel.app/query.md).
