> ## 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.

# Structure du projet

> À quoi sert chaque dossier et fichier de votre projet, et comment le framework trouve ce que vos fichiers déclarent

Un projet créé avec `create chapterjs`, à partir du modèle `minimal`, ressemble à ceci. Tout ce que fait votre bot vit dans `src/` ; le reste est de la configuration que vous touchez rarement.

**my-bot**

**.chapterjs**

**public**

**src**

**presence.ts**

**.env**

**.env.example**

**.gitignore**

**package.json**

**tsconfig.json**

## Modèles

`create chapterjs` propose cinq modèles. `minimal` est présélectionné : un fichier, et le reste de ce site pour le faire grandir. Les autres sont des bots complets : lisez-les une fois le framework connu, ou partez de l’un d’eux.

| Modèle | Ce que c’est |
| - | - |
| `minimal` | Un fichier, `src/presence.ts` : le texte que Discord affiche sous le nom de votre bot. Rien d’autre. |
| `tickets` | Des tickets de support dans des fils privés : `/ticket panel` poste un bouton, qui ouvre un formulaire, qui ouvre un fil avec un bouton de prise en charge pour le staff et un bouton de fermeture ; `/ticket add` y fait entrer quelqu’un. |
| `moderation` | `/warn add`, `/warn list` et `/warn clear` (oubliés après 30 jours), `/timeout`, `/untimeout`, `/kick`, `/ban`, `/purge`, `/slowmode`, `/lock` et `/unlock`, et un journal de chaque action dans `#mod-log`. |
| `levels` | De l’XP pour chaque message, une fois par minute et par personne, un message et un rôle à chaque nouveau niveau, `/rank` (et la même chose dans le menu d’une personne), `/leaderboard` page après page, et `/xp set` pour le staff. |
| `giveaways` | `/giveaway start` poste un concours auquel on participe avec un bouton ; une tâche tire les gagnants quand le temps est écoulé, et le menu de son message le termine plus tôt ou tire à nouveau. `/giveaway list` montre ceux en cours. |

Chaque modèle sauf `minimal` a ses textes en deux langues (`en-US` et `fr`), une présence et un [fichier de test](https://www.chapterjs.org/fr/testing.md). `levels` a besoin du Message Content Intent, pour entendre chaque message : `chapterjs dev` dit où l’activer.

## `src/` : ce qu’un fichier exporte dit ce qu’il est

ChapterJS ne vous demande jamais d’enregistrer quoi que ce soit. Il charge chaque fichier de `src/`, où qu’il soit et quel que soit son nom, et fait tourner ce que les fichiers **exportent**, fabriqué avec l’une de ses fonctions :

| Déclaré avec | Ce que c’est |
| - | - |
| `command({ name, ... })` | Une commande slash : `name` est ce que les gens tapent après le `/`. `'ping'` est `/ping`, `'mod ban'` est `/mod ban` |
| `event({ name, ... })` | Une réaction à un événement : `name` est l’événement, `'memberJoin'` tourne quand quelqu’un arrive |
| `button({ ... })`, `select({ ... })`, `modal({ ... })`, `embed({ ... })` | Un bouton, un menu déroulant, un formulaire ou un embed, distingués par **le nom de leur export** : `export const again = button(...)` est le bouton `again` |
| `task({ ... })` | Quelque chose que le bot fait tout seul, régulièrement ou à des heures données, nommé d’après son export |
| `presence({ ... })` | Ce que le bot affiche sous son nom : son statut et ce qu’il fait, déclaré une fois |
| `language({ locale, ... })` | Une langue du bot : `locale` dit laquelle ; chaque fonction reçoit alors `t` |

Tous s’importent du même endroit, et un fichier peut en déclarer autant que vous voulez. Le modèle `tickets` met tout ce qui touche aux tickets dans `src/tickets/` : les commandes, le formulaire, les boutons et leurs textes, et son `tickets.ts` déclare à la fois un store et un événement. Un fichier qui déclare plusieurs choses ressemble à ceci :

```ts src/moderation/ban.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { button, command, event } from 'chapterjs';

export default command({
  name: 'ban',
  description: 'Bannit un membre',
  options: {
    target: { type: 'user', description: 'Qui bannir', required: true },
  },
  async run({ interaction, options }) {
    await interaction.reply({
      content: `Bannir ${options.target.displayName} ?`,
      components: [confirmBan({ userId: options.target.id })],
    });
  },
});

export const confirmBan = button({
  label: 'Bannir',
  style: 'danger',
  data: { userId: 'string' },
  async run({ interaction, data, guild }) {
    await guild.ban(data.userId, { reason: 'Banni avec /ban' });
    await interaction.update({ content: 'Banni.', components: [] });
  },
});

export const logged = event({
  name: 'banAdd',
  run({ user, guild }) {
    console.log(`${user.username} a été banni de ${guild.name}`);
  },
});
```

Tout fichier qui n’exporte rien de tout ça est à vous : `src/lib/greet.ts`, `src/db/index.ts`, ce que vous voulez. Il est chargé avec les autres, et vos fichiers l’importent comme d’habitude.

> [!NOTE]
>
> Comment écrire chaque sorte de déclaration est dans [Commandes](https://www.chapterjs.org/fr/commands.md),
> [Événements](https://www.chapterjs.org/fr/events.md), [Boutons](https://www.chapterjs.org/fr/components.md) et [Tâches](https://www.chapterjs.org/fr/tasks.md).

## Les noms

Deux choses se nomment elles-mêmes, parce que Discord les affiche ou parce qu’elles sont la chose même : une commande (`name: 'ping'`) et un événement (`name: 'memberJoin'`). Tout le reste est nommé par son export : `export const again = button(...)` est le bouton `again`, `export const report = task(...)` la tâche `report`. Un export par défaut prend le nom de son fichier : `export default button(...)` dans `src/again.ts` est `again` aussi.

Discord renvoie le nom d’un bouton à chaque clic, donc renommer l’export d’un bouton casse les boutons déjà sur Discord (ils répondent « This button is not available any more. ») ; déplacer le fichier ne change rien.

> [!WARNING]
>
> Deux choses ne peuvent pas porter le même nom : deux commandes nommées
> `ping`, ou deux boutons exportés sous `confirm`. La seconde est signalée
> avec les deux fichiers et laissée de côté.

## Imports

Vos fichiers sont du TypeScript, exécuté directement par Node. Un import relatif n’a pas besoin d’extension, et un dossier avec un fichier `index` fonctionne aussi :

```ts src/commands/hello.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { command } from 'chapterjs';
import { greet } from '../lib/greet'; // src/lib/greet.ts
import { db } from '../db'; // src/db/index.ts

export default command({
  name: 'hello',
  description: 'Dit bonjour',
  async run({ interaction, user }) {
    db.visits += 1;
    await interaction.reply(greet(user.displayName));
  },
});
```

```ts src/lib/greet.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
export function greet(name: string): string {
  return `Bonjour ${name} !`;
}
```

```ts src/db/index.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
export const db = { visits: 0 };
```

Écrire l’extension fonctionne aussi : `'../lib/greet.ts'`.

Les paquets de `node_modules` s’importent comme d’habitude. Chaque fichier de `src/` est surveillé : dans [`chapterjs dev`](https://www.chapterjs.org/fr/run/dev), enregistrer `src/lib/greet.ts` recharge chaque fichier qui l’utilise. Un test à côté de votre code (`greet.test.ts`, `greet.spec.ts`) n’est jamais chargé par le bot : [`chapterjs test`](https://www.chapterjs.org/fr/testing) le lance.

## `public/` : les fichiers que votre bot envoie

Images, documents, sons : mettez-les dans `public/`, dans les dossiers que vous voulez, et envoyez-en un avec `asset('photos/monday.png')` dans les `files` d’un message. Votre éditeur liste les fichiers du dossier pendant que vous tapez, et `chapterjs dev` garde cette liste à jour pendant que vous ajoutez des fichiers. Un fichier est lu quand le message est envoyé. Voir [Fichiers](https://www.chapterjs.org/fr/messages.md#fichiers). Un son de `public/` se joue dans un salon vocal de la même façon, avec `voice.play(asset('intro.ogg'))` : voir [Jouer en vocal](https://www.chapterjs.org/fr/voice.md).

## `.chapterjs/` : généré, ignoré, supprimable sans risque

Ce dossier est écrit par ChapterJS, et git l’ignore. Il contient :

| | Ce que c’est |
| - | - |
| `types/` | Ce que votre projet ajoute aux types de `chapterjs` : les fichiers de `public/` que `asset()` propose, vos langues, qui typent `t`, et vos commandes. Votre éditeur le lit. |
| `cache/` | Ce qui a été enregistré sur Discord la dernière fois, pour que redémarrer votre bot ne coûte aucune requête. |
| `build/` | Votre bot compilé, écrit par [`chapterjs build`](https://www.chapterjs.org/fr/run/build). |

Il est écrit quand vous installez votre projet (`postinstall` lance `chapterjs sync`) et à chaque démarrage de `chapterjs dev` ou `chapterjs build`. Si votre éditeur ne connaît pas les fichiers de `public/` ou vos textes, lancez `chapterjs sync` : voir la [référence du CLI](https://www.chapterjs.org/fr/reference/cli.md#chapterjs-sync).

## `.env`

Deux valeurs, lues par [`chapterjs dev`](https://www.chapterjs.org/fr/run/dev) ; [`chapterjs start`](https://www.chapterjs.org/fr/run/start) n’a besoin que de la première :

```bash .env theme={"theme":{"light":"github-light","dark":"vesper"}}
BOT_TOKEN=
DEV_GUILD_ID=
```

Où les trouver est dans [Votre application Discord](https://www.chapterjs.org/fr/setup/discord-application.md). Le vrai environnement l’emporte sur le fichier : chez un hébergeur, vous donnez `BOT_TOKEN` dans ses réglages et n’envoyez aucun `.env`. Deux de plus, `REDIS_URL` et `REDIS_PASSWORD`, ne comptent que quand un store garde ses données dans Redis : voir [Stockage](https://www.chapterjs.org/fr/storage.md#dans-redis).

> [!WARNING]
>
> Votre token est un mot de passe : ne le partagez jamais, et ne committez
> jamais `.env`. Les projets créés avec `create chapterjs` l’ignorent déjà dans
> git.

## `package.json`

Les scripts de votre projet lancent le [CLI](https://www.chapterjs.org/fr/reference/cli.md) :

| Script | Lance | Quand |
| - | - | - |
| `dev` | `chapterjs dev` | Pendant que vous écrivez votre bot |
| `build` | `chapterjs build` | Avant de le mettre en ligne |
| `start` | `chapterjs start` | Sur la machine qui l’héberge |
| `test` | `chapterjs test` | Pour vérifier chaque fichier, et vos scénarios, sans Discord |
| `typecheck` | `tsc -b` | Pour vérifier les types de tout le projet depuis un terminal |
| `postinstall` | `chapterjs sync` | Tout seul, après chaque installation |

`chapterjs` est la seule dépendance de votre bot, à la version exacte qu’avait `create chapterjs` (`"chapterjs": "0.3.0"`, sans `^`) : votre projet ne change de version que quand vous lancez la commande que [`chapterjs dev` vous donne](https://www.chapterjs.org/fr/run/dev#une-nouvelle-version-de-chapterjs). TypeScript et `@types/node` sont des dépendances de développement : elles vérifient votre code, et ne servent pas à le faire tourner.

## `tsconfig.json`

Il ne contient que des options du compilateur et une référence vers `./.chapterjs`, qui est là où se trouve le vrai projet : chaque fichier de `src/`, plus ce que le framework écrit sur votre projet. Gardez-le ainsi.

> [!WARNING]
>
> Un simple `tsc` ne vérifie rien dans un projet ChapterJS. Utilisez le script
> `typecheck`, qui lance `tsc -b` : c’est ce que suit votre éditeur aussi.

## Avec pnpm : un fichier de plus

pnpm refuse d’installer un projet qui a esbuild quelque part dans ses dépendances (ici, à travers `chapterjs`) tant qu’on ne lui a pas dit si le script d’installation d’esbuild peut tourner. Il ne peut pas, et esbuild n’en a pas besoin. `create chapterjs` écrit la réponse pour vous ; dans un projet créé autrement, créez-le à côté de `package.json` :

```yaml pnpm-workspace.yaml theme={"theme":{"light":"github-light","dark":"vesper"}}
allowBuilds:
  esbuild: false
ignoredBuiltDependencies:
  - esbuild
```

> [card] [Commandes](https://www.chapterjs.org/fr/commands.md)
>
> Une commande slash, des options typées pour vous.

> [card] [Événements](https://www.chapterjs.org/fr/events.md)
>
> Une réaction à tout ce qui se passe sur Discord.


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