> ## Documentation Index
> Fetch the complete documentation index at: https://www.chapterjs.org/llms.txt
> Use this file to discover all available pages before exploring further.

# store()

> Tout ce que store() déclare et fait : la portée, l’expiration, les clés, et chaque appel

`store()` déclare un store, depuis n’importe quel fichier de `src/`, et le nom de son export est le nom du store. Il prend un objet, `StoreConfig`, ou rien.

```ts src/warnings.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { store } from 'chapterjs';

export const warnings = store<string[]>({ expires: '30d' });
```

> [!NOTE]
>
> Comment utiliser un store, où sont ses données et comment marche l’expiration est dans le [guide](https://www.chapterjs.org/fr/storage.md). Cette page liste ce qui existe.

## store()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
store<T>(config?: StoreConfig): Store<T>
```

Déclare un store : des données que le bot garde d’un redémarrage à l’autre, typées par ce qu’il contient. Exportez le résultat depuis n’importe quel fichier de `src/` : le nom de l’export est le nom du store, et de son fichier dans `data/` (ou de ses clés dans Redis, avec `storage: 'redis'`). Par serveur sauf si `scope: 'global'` est donné, avec une expiration si `expires` l’est.

## StoreConfig

Ce qu’un fichier donne à `store()`.

**scope** `StoreScope`

`'guild'` (le défaut) : les données sont gardées par serveur, et une fonction qui tourne dans un serveur lit et écrit les données de ce serveur, sans rien dire. `'global'` : un seul jeu de données pour tout le bot.

**storage** `StoreStorage`

Où les données sont gardées : `'file'` (le défaut), un fichier dans le dossier `data/` du projet, ou `'redis'`, le Redis de `REDIS_URL` dans `.env`. Seuls les stores qui disent `'redis'` y écrivent quelque chose.

**expires** `Duration`

Combien de temps une valeur est gardée, sauf si `set()` dit autrement : un nombre et une unité, `s`, `m`, `h` ou `d`, comme `'10m'`, `'1d'` ou `'1h30m'`. Gardée pour toujours par défaut.

### StoreScope

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
type StoreScope = 'guild' | 'global';
```

Où les données d’un store sont gardées à part : par serveur, ou une seule fois pour tout le bot.

### StoreStorage

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
type StoreStorage = 'file' | 'redis';
```

Où un store garde ses données : ce que `storage` de sa config nomme.

## Store

Ce que renvoie `store()` : une déclaration que le framework trouve dans les exports d’un fichier. C’est un `ScopedStore` pour le serveur où le code tourne, plus :

### in()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
in(guild: Guild | string): ScopedStore<T>
```

Le même store, pour un serveur : ce qu’une tâche, ou une fonction qui tourne hors d’un serveur, utilise pour lire et écrire les données de ce serveur.

## ScopedStore

Un store, lu et écrit pour un serveur ou pour tout le bot.

### get()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
get(key: StoreKey): Promise<T | undefined>
```

La valeur à `key`, ou `undefined` quand il n’y en a pas, ou qu’elle a expiré.

### set()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
set(key: StoreKey, value: T, options?: StoreSetOptions): Promise<void>
```

Garde `value` à `key`. La valeur doit être du JSON : pas de `Date`, de `Map` ni d’instance de classe.

### update()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
update(key: StoreKey, change: (current: T | undefined) => T, options?: StoreSetOptions): Promise<T>
```

Lit la valeur à `key` et garde ce que renvoie `change`, d’un trait : rien de ce qui est écrit entre-temps n’est perdu, même par un autre processus. `change` reçoit `undefined` quand il n’y a pas encore de valeur, et peut tourner de nouveau quand la valeur a changé entre-temps : gardez-le un simple calcul. L’expiration reste ce qu’elle était, sauf si `options` dit autrement.

### increment()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
increment(this: ScopedStore<number>, key: StoreKey, by?: number, options?: StoreSetOptions): Promise<number>
```

Ajoute `by` (1 par défaut, négatif pour retirer) au nombre à `key`, en partant de 0, d’un trait comme `update()`, et renvoie le nouveau nombre. Seulement pour un store de nombres.

### delete()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
delete(key: StoreKey): Promise<boolean>
```

Oublie la valeur à `key`. `true` quand il y en avait une.

### getMany()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
getMany(keys: readonly StoreKey[]): Promise<(T | undefined)[]>
```

Les valeurs de plusieurs clés d’un coup, dans leur ordre : `undefined` pour une clé qui n’en a pas.

### setMany()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
setMany(values: readonly (readonly [key: StoreKey, value: T])[], options?: StoreSetOptions): Promise<void>
```

Garde plusieurs valeurs d’un coup, chacune avec les mêmes `options`. Chaque valeur est vérifiée avant que rien ne soit écrit.

### deleteAll()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
deleteAll(prefix?: StoreKey): Promise<number>
```

Oublie chaque valeur dont la clé commence par `prefix`, ou chaque valeur du store (du serveur, pour un store par serveur) sans préfixe. Renvoie combien il y en avait.

### entries()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
entries(prefix?: StoreKey): Promise<StoreEntry<T>[]>
```

Chaque entrée, ou celles dont la clé commence par `prefix`, sans ordre particulier. Les expirées sont laissées de côté.

### ttl()

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
ttl(key: StoreKey): Promise<number | null | undefined>
```

Combien de temps la valeur à `key` est encore gardée, en millisecondes : `null` quand elle est gardée pour toujours, `undefined` quand il n’y a pas de valeur.

## StoreKey

```ts theme={"theme":{"light":"github-light","dark":"vesper"}}
type StoreKey = string | readonly string[];
```

Une clé d’un store : un texte, ou une liste de textes pour une clé en plusieurs parties (`[channel.id, message.id]`), qu’`entries()` peut ensuite lister par préfixe.

## StoreSetOptions

Ce que `set()` et `update()` prennent en plus de la valeur.

**expires** `Duration | Date | null`

Combien de temps la valeur est gardée : une durée comme `'10m'`, une `Date`, ou `null` pour la garder pour toujours. L’`expires` du store par défaut.

## StoreEntry

Une entrée d’un store, comme `entries()` les liste.

**key** `readonly string[]` *required*

La clé, chacune de ses parties (le serveur laissé de côté pour un store par serveur).

**value** `T` *required*

La valeur.

**expires** `Date | null` *required*

Quand la valeur expire, ou `null` quand elle est gardée pour toujours.

## Où vivent les données

Un fichier par store, `data/<nom>.json` à la racine du projet : `{ "version": 1, "entries": [[key, value, expiresAt], ...] }`, avec `expiresAt` en millisecondes depuis l’epoch ou `null`. Écrit peu après un changement, d’un seul bloc (un fichier temporaire, puis un renommage), et quand le bot s’arrête. Les entrées expirées sont retirées quand le fichier est lu, quand on les demande, et chaque minute.

En production sur plusieurs processus, le processus que vous avez lancé garde les données et répond aux autres par IPC.

Avec `storage: 'redis'`, une clé Redis par valeur : `<nom>:<partie>:<partie>` (l’id du serveur est la première partie d’un store par serveur ; `:`, `*`, `?`, `[`, `]`, `\` et `%` dans une partie s’écrivent `%XX`), sa valeur le JSON de la valeur, son expiration posée sur la clé (`PX`), pour que Redis l’oublie seul. `chapterjs dev` met `dev:` devant chaque clé. `entries()` est un `SCAN` sur le préfixe. Chaque processus atteint Redis lui-même. `update()` et `increment()` sont une transaction (`WATCH`, `MULTI`, `EXEC`), refaite sur la nouvelle valeur quand un autre processus a écrit la clé entre-temps, sur une connexion à elles (4 au plus à la fois par processus, en plus de la principale) ; les mises à jour d’une même clé dans un processus s’attendent l’une l’autre. L’adresse vient de `REDIS_URL` et `REDIS_PASSWORD` (voir la [référence du CLI](https://www.chapterjs.org/fr/reference/cli.md#env)) ; un Redis qui ne répond pas arrête `dev` et `start` avant d’atteindre Discord, et la connexion revient d’elle-même une fois qu’elle a été faite.

## Erreurs

| Quand | Message |
| - | - |
| `update()` n’est jamais passé : la valeur a changé 50 fois entre-temps | `The value of hits changed 50 times while update() was trying to change it: it is written too often by too many at once. Keep what changes this often under several keys.` |
| `increment()` sur une valeur qui n’est pas un nombre | `increment() adds to a number, and the value at ["a"] is a string: use update() to change it.` |
| `setMany()` avec une valeur qui n’est pas du JSON | `the value of item 1 is a Date, which JSON can't hold: …` (rien n’est écrit) |
| Un store par serveur est utilisé là où aucun serveur n’est connu | `<name> is a store per server, and this code does not run in one: use <name>.in(guild) to say which server, or declare the store with scope: 'global'.` |
| Un store qui n’est pas exporté est utilisé | `This store was not loaded by ChapterJS: a store is exported from a file of src/ (export const name = store()), and used once the bot started.` |
| Une valeur n’est pas du JSON | `the value.list[0].at is a Date, which JSON can't hold: a store keeps JSON (texts, numbers, booleans, lists and plain objects). Keep what you need of it: an id, a text, a number.` |
| Une clé est vide, ou pas faite de textes | `A key of a store is a text that is not empty, or a list of such texts with at least one.` |
| Deux stores ont le même nom | `✗ src/b.ts (hits) There is already a store named hits, in src/a.ts: the name of the export is the name of the store, so rename one of them.` |
| Un fichier de `data/` a été modifié à la main | `data/hits.json is not a file ChapterJS wrote: fix it, or delete it to start the store empty.` |
| Un store dit `storage: 'redis'` et `REDIS_URL` n’est pas réglé | `✗ src/sessions.ts (sessions) sessions is kept in Redis (storage: 'redis'), but REDIS_URL is not set: add it to .env (like redis://localhost:6379) and start again, or remove storage: 'redis' to keep its data in data/.` |
| Redis ne répond pas au démarrage du bot | `✗ Redis at localhost:6379 can't be reached: nothing answers there. Start Redis, or check REDIS_URL in .env.` |
| Redis refuse le mot de passe, ou en demande un | `✗ Redis at localhost:6379 refused the password: check REDIS_PASSWORD (or the password in REDIS_URL) in .env.` / `✗ Redis at localhost:6379 asks for a password: set REDIS_PASSWORD (or the password in REDIS_URL) in .env.` |
| Redis disparaît pendant que le bot tourne | `⚠ Redis at localhost:6379 closed the connection. Trying again every few seconds.` puis `↻ Redis at localhost:6379 is back` |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.