From 4a829b5c8e4743e7508c47e62af404b33492bcc7 Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:25:55 +0200 Subject: [PATCH 01/14] docs: reorganize old documentation into _internal/ - Move specs/, review/, and functional.md into _internal/ - Update docs/README.md with VitePress instructions - Update AGENTS.md with docs workspace commands --- AGENTS.md | 6 + docs/.gitignore | 4 + docs/.vitepress/config.ts | 125 ++ docs/README.md | 56 +- docs/_internal/functional.md | 66 + .../review/config-completion-findings.md | 138 ++ .../review/dev-guild-commands-findings.md | 79 + docs/_internal/specs/autopin.md | 76 + docs/_internal/specs/module-config.md | 248 +++ docs/_internal/specs/thread-creator-queue.md | 47 + docs/package.json | 15 + docs/pnpm-lock.yaml | 1620 +++++++++++++++++ pnpm-lock.yaml | 1557 +++++++++++++++- pnpm-workspace.yaml | 6 +- 14 files changed, 4000 insertions(+), 43 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/.vitepress/config.ts create mode 100644 docs/_internal/functional.md create mode 100644 docs/_internal/review/config-completion-findings.md create mode 100644 docs/_internal/review/dev-guild-commands-findings.md create mode 100644 docs/_internal/specs/autopin.md create mode 100644 docs/_internal/specs/module-config.md create mode 100644 docs/_internal/specs/thread-creator-queue.md create mode 100644 docs/package.json create mode 100644 docs/pnpm-lock.yaml diff --git a/AGENTS.md b/AGENTS.md index 7b8592a..502eefd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,6 +14,10 @@ pnpm prisma:consolidate # merge *.prisma module files → src/prisma/schema.pr pnpm prisma:generate # generate Prisma client (required before build) pnpm prisma:migrate # create and apply a migration pnpm prisma:studio # open Prisma Studio + +# Documentation (in docs/) +pnpm --filter omnibot-docs dev # start VitePress dev server +pnpm --filter omnibot-docs build # build static site ``` Run the whole stack in one command with [pitchfork](https://github.com/jdx/pitchfork) (pinned in `.mise.toml`, so `mise install` provides it): @@ -42,6 +46,8 @@ See [`docs/`](docs/README.md) for the full developer guide: | Prisma multi-file schema | [docs/prisma.md](docs/prisma.md) | | Functional behavior | [docs/functional.md](docs/functional.md) | +The docs are also published as a VitePress site at [`docs/`](docs/) — run `pnpm --filter docs dev` to preview. + ## Key rules - Never edit `src/prisma/schema.prisma` directly — edit the module's own `*.prisma` file and run `pnpm prisma:consolidate`. diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..203f4b2 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +dist +.vitepress/dist +.vitepress/cache diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..09b6e9b --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,125 @@ +import { defineConfig } from "vitepress"; + +const base = process.env["DOCS_BASE"] ?? "/OmniBot/"; + +export default defineConfig({ + base, + + title: "OmniBot", + description: "Documentation du bot Discord modulaire OmniBot", + + srcExclude: [ + "README.md", + "functional.md", + "modules.md", + "commands.md", + "listeners.md", + "interactions.md", + "services.md", + "prisma.md", + "specs/**", + "review/**", + "_internal/**", + ], + + cleanUrls: true, + + themeConfig: { + search: { + provider: "local", + }, + }, + + locales: { + root: { + label: "Français", + lang: "fr", + link: "/", + title: "OmniBot", + description: "Documentation du bot Discord modulaire OmniBot", + themeConfig: { + nav: [ + { text: "Guide", link: "/fr/guide/getting-started" }, + { text: "Modules", link: "/fr/guide/creating-a-module" }, + ], + sidebar: { + "/fr/guide/": [ + { + text: "Guide", + items: [ + { text: "Pour commencer", link: "/fr/guide/getting-started" }, + { + text: "Créer un module", + link: "/fr/guide/creating-a-module", + }, + { text: "Commandes", link: "/fr/guide/commands" }, + { text: "Écouteurs", link: "/fr/guide/listeners" }, + { text: "Interactions", link: "/fr/guide/interactions" }, + { text: "Configuration", link: "/fr/guide/configuration" }, + { text: "Services", link: "/fr/guide/services" }, + { text: "Base de données", link: "/fr/guide/database" }, + ], + }, + ], + }, + outline: { + label: "Sur cette page", + }, + returnToTopLabel: "Retour en haut", + sidebarMenuLabel: "Menu", + darkModeSwitchLabel: "Apparence", + lightModeSwitchTitle: "Passer en mode clair", + darkModeSwitchTitle: "Passer en mode sombre", + docFooter: { + prev: "Page précédente", + next: "Page suivante", + }, + }, + }, + en: { + label: "English", + lang: "en", + link: "/en/", + title: "OmniBot", + description: "OmniBot modular Discord bot documentation", + themeConfig: { + nav: [ + { text: "Guide", link: "/en/guide/getting-started" }, + { text: "Modules", link: "/en/guide/creating-a-module" }, + ], + sidebar: { + "/en/guide/": [ + { + text: "Guide", + items: [ + { text: "Getting Started", link: "/en/guide/getting-started" }, + { + text: "Creating a Module", + link: "/en/guide/creating-a-module", + }, + { text: "Commands", link: "/en/guide/commands" }, + { text: "Listeners", link: "/en/guide/listeners" }, + { text: "Interactions", link: "/en/guide/interactions" }, + { text: "Configuration", link: "/en/guide/configuration" }, + { text: "Services", link: "/en/guide/services" }, + { text: "Database", link: "/en/guide/database" }, + ], + }, + ], + }, + outline: { + label: "On this page", + }, + returnToTopLabel: "Return to top", + sidebarMenuLabel: "Menu", + darkModeSwitchLabel: "Appearance", + lightModeSwitchTitle: "Switch to light mode", + darkModeSwitchTitle: "Switch to dark mode", + docFooter: { + prev: "Previous page", + next: "Next page", + }, + }, + }, + }, +}); diff --git a/docs/README.md b/docs/README.md index a42020d..8d0f5c2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,49 +1,23 @@ -# Guide de Développement AsyncMod +# Documentation OmniBot -Bienvenue dans le guide de développement d'AsyncMod ! Cette documentation vous expliquera comment créer des modules, -commandes et listeners pour étendre les fonctionnalités du bot Discord. +La documentation a été migrée vers [VitePress](https://vitepress.dev/). -## Structure de la Documentation +Pour lancer le serveur de documentation en local : -- [**Modules**](modules.md) - Comment créer et structurer un module -- [**Commandes**](commands.md) - Comment créer des commandes slash -- [**Listeners**](listeners.md) - Comment écouter et réagir aux événements Discord -- [**Interactions**](interactions.md) - Comment gérer les boutons, menus et modales -- [**Services**](services.md) - Comment créer des services pour la logique métier -- [**Prisma**](prisma.md) - Guide sur l'utilisation de Prisma pour la base de données -- [**Fonctionnel**](functional.md) - Comportement visible par les utilisateurs Discord - -## Architecture du Projet - -AsyncMod utilise un système de modules modulaire où chaque fonctionnalité est encapsulée dans son propre module. Chaque -module peut contenir des commandes, des listeners et sa propre logique métier. - -## Conventions de Nommage +```bash +pnpm --filter docs dev +``` -Le projet utilise un système de nommage inspiré d'Angular avec des suffixes pour identifier le type de fichier : +Pour construire la version statique : -- `*.module.ts` - Fichiers de modules (ex: `example.module.ts`) -- `*.command.ts` - Fichiers de commandes Discord (ex: `test.command.ts`) -- `*.listener.ts` - Fichiers d'événements Discord (ex: `message.listener.ts`) -- `*.button.ts` / `*.modal.ts` / `*.select.ts` - Handlers d'interactions -- `*.service.ts` - Fichiers de services (ex: `user.service.ts`) -- `*.prisma` - Modèles de base de données Prisma (ex: `users.prisma`) +```bash +pnpm --filter docs build +``` -Cette convention permet d'identifier rapidement le rôle de chaque fichier dans le projet. +Les sources sont organisées dans `docs/` : -## Structure du Projet +- `en/` — Documentation en anglais +- `fr/` — Documentation en français +- `_internal/` — Anciens fichiers et spécifications internes -``` -src/ -├── modules/ # Dossier contenant tous les modules du bot -│ ├── mon-module-ici/ # Module -│ │ ├── commands/ # Commandes du module -│ │ ├── listeners/ # Listeners du module -│ │ ├── models/ # Modèles de données pour la base de données -│ │ ├── services/ # Services du module -│ │ └── mon-module.module.ts # Fichier principal du module -├── lib/ # Bibliothèques utile pour les modules -└── core/ # Système central, services et gestion des modules - ├── loaders/ # Chargeurs de modules - └── services/ # Services principaux -``` +> L'ancienne documentation markdown simple a été déplacée dans `docs/_internal/`. diff --git a/docs/_internal/functional.md b/docs/_internal/functional.md new file mode 100644 index 0000000..78c3e01 --- /dev/null +++ b/docs/_internal/functional.md @@ -0,0 +1,66 @@ +# Fonctionnement du bot + +Documentation du comportement visible par les utilisateurs et administrateurs de serveur Discord. + +--- + +## Module Core + +Toujours actif, non désinstallable. Fournit la gestion des modules pour les administrateurs. + +### `/modules` — Gérer les modules du serveur + +**Permission requise :** Administrateur + +Affiche la liste de tous les modules disponibles avec leur statut sur le serveur (activé/désactivé), leur version activée, et leur description. Chaque module dispose d'un bouton **Activer** (vert) ou **Désactiver** (rouge) qui prend effet immédiatement. + +--- + +## Module Thread Creator + +Crée automatiquement un fil de discussion sous chaque nouveau message dans un salon configuré. Remplace le bot Needle. + +### Comportement automatique + +Dès qu'un message est posté dans le salon configuré : + +1. Le bot crée un fil dont le nom est généré depuis le template configuré +2. Si un message de bienvenue est configuré, le bot le poste dans le fil + +**Variables disponibles dans le template de nom :** +| Variable | Valeur | +|---|---| +| `{messageAuthor}` | Nom d'affichage ou pseudo de l'auteur | +| `{messageContent}` | 50 premiers caractères du message | +| `{timestamp}` | Heure au format `JJ/MM HH:MM` (locale française) | + +**Template par défaut :** `Discussion - {messageAuthor}` +**Message de bienvenue par défaut :** `💬 Utilisez ce fil pour discuter de ce sujet !` + +**Limites :** + +- Noms de fils tronqués à 100 caractères (limite Discord) +- Rate limit : 5 fils max par fenêtre de 10 secondes par serveur — les créations excédentaires sont **mises en file d'attente** (FIFO, par serveur) et traitées dès que la fenêtre se libère, au lieu d'être ignorées. File en mémoire : perdue au redémarrage. +- Messages de bots ignorés +- Ne fonctionne pas dans les fils, salons vocaux, forum ou annonces + +**Erreurs gérées silencieusement :** + +- Message supprimé avant création du fil +- Limite de fils atteinte sur le salon +- Permissions insuffisantes + +### Configuration — `/config thread-creator` + +Depuis la v2.0.0, le module utilise le système de configuration générique. Il n'a +plus de commande dédiée : la configuration se fait via `/config thread-creator` +(réservé aux administrateurs) et l'activation/désactivation via `/modules`. + +| Champ | Type | Description | +| -------------------- | -------------- | -------------------------------------------------------------------------------------------- | +| `channels` | Salons (liste) | Salons à surveiller (un ou plusieurs, multi-select). Liste vide = rien n'est surveillé. | +| `welcomeMessage` | Texte | Message posté automatiquement dans chaque fil créé. | +| `threadNameTemplate` | Texte | Template du nom des fils — variables : `{messageAuthor}`, `{messageContent}`, `{timestamp}`. | + +Il n'y a plus de flag `actif` : désactiver le module via `/modules` arrête la +surveillance sans effacer la configuration. diff --git a/docs/_internal/review/config-completion-findings.md b/docs/_internal/review/config-completion-findings.md new file mode 100644 index 0000000..5f9f45a --- /dev/null +++ b/docs/_internal/review/config-completion-findings.md @@ -0,0 +1,138 @@ +# Revue de code — complétion du système de configuration + +Findings de la revue du commit `feat(config): complete editing for number and +entity field types` (+ module `test-config`). À traiter ultérieurement. + +Légende statut : [ ] à faire · [x] fait + +--- + +## Bugs (à corriger) + +### [x] #1 — `config.get` ment sur la nullabilité des valeurs non définies + +- **Fichier :** `src/lib/config.ts` (`ConfigData` / `ConfigProvider.get`), + `src/core/services/config.service.ts` (`createDefaultConfigForModule`) +- **Problème :** un champ sans `defaultValue` n'a pas de valeur, mais `config.get` + le type comme toujours présent (`ResolveType`). Pour les entités + (`USER`/`ROLE`/`CHANNEL`/`CATEGORY`) la valeur réelle est absente ; pour + `STRING`/`NUMBER`/`BOOLEAN` le service fabrique de faux défauts (`""`/`0`/`false`) + qui masquent l'état « non défini ». +- **Scénario d'échec :** un module fait `config.get("user").username` → compile + sans erreur → `TypeError` au runtime quand le champ n'a jamais été configuré. +- **Sémantique cible :** + - `undefined` = jamais défini ; + - `null` = vidé intentionnellement (action « clear » future) ; + - un champ **avec** `defaultValue` est toujours présent → **pas** de `| undefined`. +- **Fix proposé :** + - Typage conditionnel sur la présence de `defaultValue` : + ```ts + type ConfigEntryValue> = E extends { + defaultValue: unknown; + } + ? ResolveType + : ResolveType | undefined; + ``` + utilisé par `ConfigData` et `ConfigProvider.get`. + - Runtime : `createDefaultConfigForModule` ne pose une valeur que si + `defaultValue` est déclaré (sinon clé absente → `undefined`), au lieu de + fabriquer `""`/`0`/`false`/`null`. + - Garder `(config.get(key) ?? "").toString()` dans les `replyToEditRequest` + des handlers string/number (la valeur peut désormais être `undefined`). + +### [x] #2 — Un champ de type liste affiche un bouton « éditer » mort + +- **Fichiers :** `src/core/utils/core.messages.ts`, + `src/core/interactions/configure-module.button.ts` +- **Problème :** `configurationMessage` posait un bouton `configure-module` pour + tout type `!= BOOLEAN`, donc aussi pour un type tableau (`ListOf`). Au clic, + `configure-module.button` faisait `if (Array.isArray(schemaDef.type)) return;` + → no-op silencieux. +- **Fait :** l'édition des listes est désormais implémentée — `configure-module` + route les listes d'entités vers le multi-select et les listes scalaires vers + l'éditeur ajouter/supprimer (`scalar-list-editor.ts`). Plus de bouton mort. + +--- + +## Inefficacité (optionnel) + +### [ ] #3 — Double désérialisation dans le toggle booléen + +- **Fichier :** `src/core/interactions/toggle-option.button.ts` (l.22 puis l.36) +- **Problème :** `getConfigForModuleIn` puis `updateConfigForModuleIn` + désérialisent chacun les entités (`deserializeConfigData` → fetch guild + + entités Discord), alors qu'on ne change qu'un booléen. +- **Fix proposé :** lire la valeur booléenne courante via un chemin léger (cache + sérialisé) sans désérialiser, et laisser `updateConfigForModuleIn` faire la + seule passe nécessaire pour le rendu. +- **Note :** la racine (`deserializeConfigData` qui `fetch` la guild même sans + champ entité) est pré-existante dans `config.service.ts`, hors périmètre strict + du diff mais à garder en tête. + +--- + +## Nettoyage (optionnel) + +### [ ] #4 — Boilerplate des 4 handlers d'entité + +- **Fichiers :** `src/core/config/{user,role,channel,category}-config-handler.ts` +- **Problème :** 4 sous-classes quasi identiques (~42 lignes chacune) ne variant + que par builder de select, placeholder, filtre de type de salon et type guard. +- **Fix proposé :** rendre la base `EntitySelectConfigHandler` pilotée par une + table de données `{ selectCustomId, buildMenu, channelTypes?, guard }` plutôt + que par héritage — supprime ~150 lignes. + +### [ ] #5 — Construction de modal dupliquée string/number + +- **Fichiers :** `src/core/config/string-config-handler.ts`, + `number-config-handler.ts` +- **Problème :** le modal (ModalBuilder → ActionRow → TextInput) et le flux de + soumission sont quasi identiques ; seuls `customId`, label et validation + diffèrent. +- **Fix proposé :** helper partagé `buildTextInputModal(...)` dans + `config-edit.helpers.ts`. + +--- + +## Améliorations UX (feature config) + +### [x] #6 — Éditer/remplacer le message de config existant après soumission de modale + +- **Fichiers :** `src/core/config/string-config-handler.ts`, + `number-config-handler.ts` (soumission de modale) +- **Problème :** après soumission d'une modale, on faisait `interaction.reply(...)` + → un **nouvel** embed de configuration en doublon du message `/config`. +- **Fait :** la soumission de modale fait `interaction.update(...)` (via le garde + `isFromMessage()`) → le message de config est édité **en place**, plus de + doublon. Les toggles et select menus éditent déjà en place. + +### [x] #7 — Rendre la configuration visible de tous (non-ephemeral) + +- **Fichiers :** `src/core/commands/config.command.ts`, + `configure-module.button.ts`, `toggle-option.button.ts` +- **Problème :** modifier des paramètres qui impactent tout le serveur ne devrait + pas être caché ; mais rendre le message public expose ses boutons d'édition à + tous, or les handlers d'édition ne vérifiaient pas les permissions + (contrairement à enable/disable) → **escalade** (n'importe qui pourrait éditer). +- **Fait :** `/config` est désormais **public**. La vérification de permission + est **centralisée** : un flag déclaratif `requiresAdmin` sur + `InteractionHandler`, enforcé une seule fois par le dispatcher + (`interaction-create.listener`) avant d'exécuter le handler. Tous les handlers + d'édition config + les boutons enable/disable portent `requiresAdmin: true` ; + plus aucun appel `requireAdmin` inline (future-proof : un nouveau handler + sensible n'a qu'à poser le flag). `requireAdmin` accepte toute + `CompatibleInteraction`. Les éditeurs entité/liste restent ephemeral ; les + toggles/modales éditent le message public en place. +- **Refresh du message public :** les éditeurs entité/liste restent ephemeral + mais rafraîchissent le message public d'origine après chaque modification + (`refreshSourceConfigMessage` : id du message public threadé dans les `customId`, + puis `channel.messages.fetch(id).edit(...)`). Invariant associé : aucune vue + config n'est rendue sur un message ephemeral (le submit d'un select re-rend le + select), sinon ses boutons « Éditer » pointeraient vers un message non éditable. +- **Affichage :** les entités s'affichent en mentions rendues (`@rôle`, `#salon`) + via `renderCurrentValue` (hors backticks ; scalaires entre backticks). + +--- + +> Tâches transverses au projet (commandes guild en dev, ergonomie des imports) +> déplacées dans `AUDIT.md`. diff --git a/docs/_internal/review/dev-guild-commands-findings.md b/docs/_internal/review/dev-guild-commands-findings.md new file mode 100644 index 0000000..1c89945 --- /dev/null +++ b/docs/_internal/review/dev-guild-commands-findings.md @@ -0,0 +1,79 @@ +# Revue de code — enregistrement des commandes en mode dev (dev guild) + +Findings de la revue du travail dev-guild (audit #23 + #25, encore non commité au +moment de la revue) : `loadDevGuildCommands`, branchement dev/prod dans +`index.ts`, `env.ts`, `validate-env-vars.mjs`, script `dev`, test d'intégration. + +Le diff est globalement sain — aucun bug bloquant. Rangé du plus actionnable au +moins prioritaire. + +Légende statut : [ ] à faire · [x] fait + +--- + +## À corriger + +### [x] #1 — `loadDevGuildCommands` ne fait pas `await` sur le `rest.put` + +- **Fichier :** `src/core/loaders/command-loader.ts` (`loadDevGuildCommands`, et + même pattern dans `loadGlobalCommands`) +- **Problème :** la fonction est `async` et est `await`ée par `index.ts`, mais elle + chaîne `rest.put(...).then().catch()` sans `await`/`return`. Elle résout donc + avant la fin du PUT ; l'erreur n'est captée que dans le `.catch` (pas propagée), + et le « ready » est loggé avant l'enregistrement effectif. Incohérent avec + `installModuleCommandsIn` qui fait `await`. +- **Scénario :** un PUT qui échoue (token invalide, rate limit, body > 100 + commandes) n'est que loggé ; le démarrage continue comme si tout allait bien. +- **Fait :** `await rest.put(...)` dans un `try/catch` sur `loadDevGuildCommands` + **et** `loadGlobalCommands` (rendue `async`, désormais `await`ée dans + `index.ts`). + +### [x] #2 — Le test d'intégration n'assert pas la présence des commandes core + +- **Fichier :** `src/core/loaders/command-loader.integration.test.ts` +- **Problème :** `putBodyNames()` ne vérifiait que les commandes de module ; aucun + test n'assertait que les commandes du core sont incluses dans le body du PUT dev. +- **Scénario :** une régression retirant `coreModule.registry.commands` de + l'agrégat passerait les tests au vert → fausse couverture. +- **Fait :** `core.module.js` mocké avec une commande core connue ; assertions + ajoutées (présence de `core-cmd` dans le PUT, et un test « core seul, sans + module » → body == `["core-cmd"]`). + +--- + +## Optionnel + +### [ ] #3 — Requêtes d'état des modules séquentielles + +- **Fichier :** `src/core/loaders/command-loader.ts` (`loadDevGuildCommands`) +- **Problème :** `getModuleStateFromGuildIdIn` est `await`é par module dans la + boucle → N requêtes DB en série au démarrage. +- **Fix :** paralléliser via `Promise.all` sur les états, puis filtrer. Impact + faible aujourd'hui (peu de modules), réel à l'échelle. + +### [ ] #4 — Duplication REST + logging entre `loadGlobalCommands` et `loadDevGuildCommands` + +- **Fichier :** `src/core/loaders/command-loader.ts` +- **Problème :** construction du client REST + bloc `.then/.catch` de logging par + commande dupliqués. +- **Fix :** extraire `registerCommands(rest, route, body, label)` pour éviter la + divergence dev/prod. (Recouvre aussi la répétition de + `registry.commands.map(c => c.data.toJSON())`, présente à 3-4 endroits.) + +### [x] #5 — `index.ts` connaît les deux flux d'enregistrement (altitude) + +- **Fichier :** `src/index.ts` (handler `ClientReady`) +- **Problème :** le caller encode en détail dev (agrégat) vs prod (version-gate + + global). Toute évolution future doit choisir « dev / prod / les deux » et + toucher `index.ts`. +- **Fait :** point d'entrée unique `syncCommands(client, modules)` dans + `command-loader.ts` qui possède l'aiguillage dev/prod ; `index.ts` l'appelle en + une ligne (6888918). + +### [ ] #6 — Littéral `"development"` dupliqué + +- **Fichiers :** `bootstrap/validate-env-vars.mjs` et `src/lib/env.ts` + (`isDevMode`) +- **Problème :** la définition du mode dev (`NODE_ENV === "development"`) existe à + deux endroits ; le `.mjs` bootstrap ne peut pas importer le `.ts` facilement. +- **Fix :** extraire une petite constante partagée importable des deux côtés. diff --git a/docs/_internal/specs/autopin.md b/docs/_internal/specs/autopin.md new file mode 100644 index 0000000..73ab59d --- /dev/null +++ b/docs/_internal/specs/autopin.md @@ -0,0 +1,76 @@ +# Spec — Module Autopin + +Issues : [#15](https://github.com/AsyncCommunityDiscord/OmniBot/issues/15), [#16](https://github.com/AsyncCommunityDiscord/OmniBot/issues/16) +Priorité : moyenne + +--- + +## Objectif + +Remplacer le bot externe Pinpal. Maintenir un message "ancré" en bas d'un salon en le supprimant et le repostant à chaque nouvelle activité dans le salon. + +## Comportement + +À chaque nouveau message dans un salon configuré, le bot : + +1. Supprime le message ancré précédent (posté par le bot) +2. Reposte le contenu ancré en bas du salon +3. Mémorise l'ID du nouveau message pour la prochaine occurrence + +Le message ancré est toujours le dernier message visible dans le salon. + +## Commandes + +### `/autopin set` + +**Permission requise :** Gérer les salons + +| Paramètre | Type | Obligatoire | Description | +| ------------ | ------------- | ----------- | ----------------------------------- | +| `salon` | Salon textuel | Oui | Salon dans lequel ancrer le message | +| `message-id` | Texte | Oui | ID du message Discord à ancrer | + +Configure l'ancrage et poste immédiatement le message en bas du salon. + +### `/autopin disable` + +**Permission requise :** Gérer les salons + +Désactive l'ancrage sur le salon. Le dernier message ancré posté par le bot est supprimé ou laissé en place (à définir). + +### `/autopin status` + +**Permission requise :** Gérer les salons + +Affiche le salon configuré et un aperçu du contenu ancré. Réponse éphémère. + +## Permissions requises pour le bot + +- Lire les messages du salon +- Envoyer des messages dans le salon +- Supprimer les messages (au minimum les siens) + +## Schéma de données + +```prisma +model AutopinConfig { + guildId String @id + channelId String + pinnedContent String @db.Text + lastMessageId String? + enabled Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} +``` + +## Cas limites à gérer + +- Le bot n'a pas la permission de supprimer son propre message → warning loggé, nouvelle tentative ignorée +- Le message source (celui fourni à `/autopin set`) est supprimé → le contenu ancré doit rester opérationnel (il est stocké en base, pas recalculé) +- Salon très actif → le bot peut générer du spam de suppression/repost ; une option de fréquence minimum (ex. toutes les 5 minutes) est envisagée comme amélioration ultérieure + +## Ce qui est hors scope (v1) + +- Plusieurs messages ancrés par salon +- Fréquence de réancrage configurable diff --git a/docs/_internal/specs/module-config.md b/docs/_internal/specs/module-config.md new file mode 100644 index 0000000..d332920 --- /dev/null +++ b/docs/_internal/specs/module-config.md @@ -0,0 +1,248 @@ +# Spec — Système de configuration des modules + +Issue : [#14](https://github.com/AsyncCommunityDiscord/OmniBot/issues/14) +Priorité : haute — assignée à RedsTom, jalon « Finish the module library ». + +> Cette spec décrit l'architecture **réellement implémentée** (branche `feat/config`) +> et formalise le travail restant pour clore la fonctionnalité. Elle remplace la +> proposition normalisée initiale (`/config view|set|reset` + table `ModuleConfig`), +> abandonnée au profit d'une UI interactive et d'un stockage en blob JSON. + +--- + +## Objectif + +Permettre à chaque module de déclarer un schéma de configuration **typé**, +persistant en base par serveur, consultable et modifiable par les administrateurs +via une interface Discord interactive. + +## Types de champs supportés + +| Type | Saisie | Stockage (JSON) | Lecture (désérialisé) | +| ---------- | ------------------------ | ---------------- | --------------------- | +| `STRING` | Modal (texte) | `string` | `string` | +| `NUMBER` | Modal (texte → nombre) | `number` | `number` | +| `BOOLEAN` | Bouton toggle | `boolean` | `boolean` | +| `USER` | Select menu utilisateur | `string` (id) | `User` | +| `ROLE` | Select menu rôle | `string` (id) | `Role` | +| `CHANNEL` | Select menu salon | `string` (id) | `Channel` | +| `CATEGORY` | Select menu catégorie | `string` (id) | `CategoryChannel` | +| `ENUM` | Select menu (choix fixe) | `string` (choix) | union littérale¹ | + +¹ `ENUM` représente un choix parmi un ensemble fixe déclaré sur l'entrée via +`options`. La valeur stockée et lue est l'une de ces options (un `string`). Si +`options` est déclaré `as const`, `config.get(...)` est typé comme l'**union +littérale** des valeurs (`"light" | "dark"`), sinon `string`. Voir +[Type `ENUM`](#type-enum-choix-fixe). + +### Listes (`ListOf`) + +N'importe quel type peut être déclaré en **liste** via `type: [ConfigType.X]`. La +valeur lue est alors un tableau (`X[]`). L'édition dépend du type de base : + +- **Entités** (`USER`/`ROLE`/`CHANNEL`/`CATEGORY`) → **multi-select** natif + (jusqu'à 25 éléments, pré-sélection des valeurs courantes). +- **`ENUM`** (`[ConfigType.ENUM]`) → **multi-select** sur les `options` déclarées + (min 0 pour autoriser le vidage, max = nombre d'options) ; pré-sélection des + valeurs courantes. +- **Scalaires** (`STRING`/`NUMBER`) → **éditeur dédié** : un message listant + chaque élément avec un bouton _Supprimer_, plus un bouton _Ajouter_ qui ouvre + une modale validée par le type. +- **Booléens en liste** (`[BOOLEAN]`) → même éditeur, mais chaque élément est un + **toggle** (bascule vrai/faux en place) ; _Ajouter_ insère directement un + `false` (pas de modale). + +## API pour les modules + +Un module déclare son schéma dans `defineModule({ ..., config: { ... } })` : + +```ts +config: { + logChannel: { + name: "Salon de logs", + description: "Salon où poster les logs", + type: ConfigType.CHANNEL, + }, + maxWarnings: { + name: "Avertissements max", + description: "Nombre d'avertissements avant sanction", + type: ConfigType.NUMBER, + defaultValue: 3, + }, +} +``` + +Lecture des valeurs (désérialisées) côté composants du module : + +```ts +async execute(interaction, config) { + const channel = config.get("logChannel"); // Channel | undefined (pas de défaut) + const max = config.get("maxWarnings"); // number (a un defaultValue) +} +``` + +Typage des valeurs : un champ **avec** `defaultValue` est toujours présent ; un +champ **sans** défaut peut être `undefined` (jamais défini). `null` est réservé à +une valeur effacée intentionnellement. Voir `ConfigEntryValue` dans +`src/lib/config.ts`. + +### Type `ENUM` (choix fixe) + +Un champ `ENUM` déclare un ensemble fixe de valeurs autorisées via `options` : + +```ts +config: { + logLevel: { + name: "Niveau de log", + description: "Verbosité des logs", + type: ConfigType.ENUM, + options: ["debug", "info", "warn", "error"] as const, // `as const` → union littérale + defaultValue: "info", + }, + // Liste : plusieurs choix parmi le même ensemble (multi-select) + enabledFeatures: { + name: "Fonctionnalités", + description: "Modules optionnels activés", + type: [ConfigType.ENUM], + options: ["welcome", "logs", "automod"] as const, + }, +} +``` + +- `options` est **obligatoire** sur une entrée `ENUM` (le type l'exige). +- `as const` fait que `config.get("logLevel")` est typé `"debug" | "info" | +"warn" | "error"` (l'union littérale) ; sans `as const`, c'est `string`. +- La valeur est stockée telle quelle (un `string`) ; aucune désérialisation. + +Le `ConfigProvider` est injecté automatiquement dans `execute`/`complete`/`check` +des commandes, listeners et interaction handlers (voir +`interaction-create.listener.ts`, `listener-loader.ts`). + +## Persistance + +Stockage en **un blob JSON par serveur** (et non une table normalisée) : + +```prisma +model GuildConfiguration { + guildId String @id + data Json +} +``` + +- `data` mappe `moduleId -> { clé: valeur sérialisée }`. +- Les entités Discord (user/role/channel/category) sont stockées par **id** et + réhydratées à la lecture par `ConfigService.deserializeConfigData`. +- Un cache en mémoire (`configCache`) évite un aller-retour base à chaque lecture ; + il est invalidé à chaque écriture. +- Les valeurs par défaut sont matérialisées à la création de la config du serveur. + +## Interface admin + +### Commande `/config ` + +- Option `module` requise, avec autocomplétion (modules activés + core). +- Réservée aux administrateurs (`setDefaultMemberPermissions`). +- Réponse **publique** (Components V2) : une modification impactant tout le + serveur ne doit pas être cachée. Comme le message est public, les + interactions d'édition sont réservées aux admins via le flag déclaratif + `requiresAdmin` (sur `InteractionHandler`), enforcé centralement par le + dispatcher d'interactions. +- Liste chaque option : nom, description, type, valeur courante, et un accessoire + d'édition selon le type : + - bouton **toggle** pour les booléens (`toggle-option`) ; + - bouton **éditer** pour tous les autres types (`configure-module`). +- **Pagination** : chaque champ coûte 3 composants (section + texte + bouton) et + Discord plafonne un message à **40 composants**. Le panneau affiche donc + `CONFIG_FIELDS_PER_PAGE` champs par page (10) avec une barre _◀ Précédent / + Suivant ▶_ (`config-page::`) qui ré-affiche le panneau en place. + La barre n'apparaît qu'au-delà d'une page. Après une édition, le panneau se + ré-affiche sur la **page contenant le champ modifié** : cette page est + **déduite** de la position de la clé dans le schéma (`configPageOfKey`), donc + aucun `page` n'est threadé dans les `customId` (contrairement à + `sourceMessageId`). Comme un admin ne peut cliquer que sur la page affichée, la + page déduite est toujours celle qu'il regardait. +- **Limitation multi-admin** (assumée) : le panneau étant **un seul message + public partagé**, sa page courante est un état **global**, pas par-utilisateur. + Deux admins ne peuvent pas naviguer indépendamment, et l'action de l'un + re-rend le message pour tous. C'est purement cosmétique (la persistance est + toujours correcte) et rare ; le seul vrai correctif serait un panneau ephemeral + par-utilisateur, écarté par choix (panneau public, voir #7). + +### Flux d'édition + +Le bouton `configure-module::` ouvre l'éditeur adapté au type +(`configure-module.button.ts` route selon scalaire/entité et selon liste) : + +- `STRING`/`NUMBER` (scalaire) : **modal** texte ; +- `USER`/`ROLE`/`CHANNEL`/`CATEGORY` (scalaire ou liste) : **select menu** natif + (mono ou multi selon liste), ephemeral, V2 ; +- `ENUM` (scalaire ou liste) : **string select menu** rempli avec les `options` + de l'entrée (mono ou multi selon liste), ephemeral, V2 (`enum.config-handler.ts`) ; +- listes scalaires (`STRING`/`NUMBER`/`BOOLEAN`) : **éditeur ajouter/supprimer** + (`scalar-list-editor.ts`). + +La soumission (modal submit, select, ou ajout/suppression) **valide**, **persiste** +via `ConfigService.updateConfigForModuleIn`, puis **réaffiche** le message public. + +- Les éditions directes (modale `STRING`/`NUMBER`, toggle booléen) éditent le + message de config **public en place** (`interaction.update`), sans nouvel embed. +- Les select menus d'entité et l'éditeur de listes scalaires sont des messages + **ephemeral** séparés (visibles du seul admin). Après chaque modification ils + rafraîchissent le message public d'origine via + `refreshSourceConfigMessage` : l'id du message public est threadé dans les + `customId` des composants de l'éditeur, et le service ré-édite ce message + (`channel.messages.fetch(id).edit(...)`). +- **Invariant** : aucune vue config (`configurationMessage`) n'est jamais rendue + sur un message ephemeral — sinon ses boutons « Éditer » pointeraient vers un + message ephemeral non éditable par id. Le submit d'un select d'entité re-rend + donc **le select** (avec la sélection à jour), pas une vue config. + +### Affichage des valeurs + +`renderCurrentValue` (dans `core.messages.ts`) rend les **entités** sous forme de +mentions **hors backticks** (Discord les affiche en `@rôle` / `#salon`) et les +**scalaires** entre backticks. Les listes sont jointes ; une valeur absente +s'affiche `—`. + +## Validation + +`ConfigValidator` (dans `src/lib/config.ts`) fournit un prédicat par type, exposé +via `ConfigTypeHandler.validate(value)` : + +- `NUMBER` : chaîne convertible en nombre fini ; +- `BOOLEAN` : `"true"` / `"false"` ; +- `USER`/`ROLE`/`CHANNEL`/`CATEGORY` : mention **ou** identifiant brut (snowflake) — + les select menus renvoyant des ids bruts ; +- `STRING` : toujours valide ; +- `ENUM` : le prédicat générique accepte tout (il n'a pas accès aux `options`) ; + l'appartenance à `options` est vérifiée par `EnumConfigHandler`, qui rejette + toute valeur soumise hors de l'ensemble déclaré. + +Pour les listes, chaque élément est validé individuellement (par valeur du +select pour les entités et les enums, à l'ajout dans l'éditeur pour les scalaires). + +## Travail réalisé + +- [x] Soumission du modal `NUMBER` (parsing + validation + sauvegarde). +- [x] Handlers `USER`/`ROLE`/`CHANNEL`/`CATEGORY` (select menus). +- [x] Ids bruts acceptés dans les validateurs d'entités. +- [x] Suppression du code mort `editionSection` / `editedField`. +- [x] Tests (lib + handlers : modal, select, éditeur de liste). +- [x] Édition des listes : multi-select pour les entités, éditeur + ajouter/supprimer pour les scalaires. +- [x] Type `ENUM` (choix fixe parmi `options`), scalaire et liste, édité via + string select menu, avec typage en union littérale. +- [x] Pagination du panneau `/config` (10 champs/page) pour respecter le plafond + de 40 composants de Discord. + +## Hors périmètre / suites possibles + +- Notification des modules sur changement de configuration (hook `onConfigChange`). + +## Migrations réalisées + +- **Thread Creator** (v2.0.0) : migré de sa table dédiée `ThreadCreatorConfig` + vers ce système générique (clean cut, sans reprise de données). La commande + `/thread-config` et le flag `enabled` ont été supprimés — la configuration se + fait via `/config thread-creator` et l'activation via `/modules`. La table + `thread_creator_configs` a été supprimée (migration `drop_thread_creator_config`). diff --git a/docs/_internal/specs/thread-creator-queue.md b/docs/_internal/specs/thread-creator-queue.md new file mode 100644 index 0000000..1abfdb8 --- /dev/null +++ b/docs/_internal/specs/thread-creator-queue.md @@ -0,0 +1,47 @@ +# Spec — Thread Creator : file d'attente de création + +Issues : [#36](https://github.com/AsyncCommunityDiscord/OmniBot/issues/36), [#37](https://github.com/AsyncCommunityDiscord/OmniBot/issues/37) +Priorité : basse + +--- + +> **Statut : implémenté.** File d'attente et multi-salons (#37) livrés : la classe `ThreadCreationQueue` (`services/thread-creation-queue.ts`) et le champ de config `channels` en `ListOf`. Voir « Implémentation » plus bas. + +## Problème (avant) + +Quand plusieurs messages arrivaient rapidement dans le salon surveillé, le rate limit de 5 fils par 10 secondes était atteint et les messages suivants étaient silencieusement ignorés. Des fils n'étaient donc jamais créés pour ces messages. + +## Comportement + +Le drop silencieux est remplacé par une **file d'attente par serveur** : si le rate limit est atteint, les créations de fils sont mises en attente et traitées dès que la fenêtre de 10 secondes se libère. + +### Règles + +- La file est propre à chaque serveur (pas de partage inter-serveurs). +- L'ordre de création respecte l'ordre d'arrivée des messages. +- Si le bot redémarre, les entrées en attente sont perdues (pas de persistance requise). +- Pas de limite de taille de file définie pour l'instant (à affiner selon les retours). + +### Pourquoi pas de persistance (décision assumée) + +La file est volontairement **en mémoire seule**. Ce qu'on perd à un redémarrage = uniquement les jobs en attente d'un **burst en cours** (le surplus au-delà de 5/10 s pas encore traité) : + +- **Sévérité faible** : les messages ne sont pas perdus (ils restent sur Discord) — on rate seulement le _fil auto_ sous certains messages d'un pic, ce qui est cosmétique et rattrapable. C'est l'ancien mode d'échec (drop sur rate limit), désormais réduit à « drop seulement si redémarrage pendant un backlog actif ». +- **Coût disproportionné** : un job référence un `Message` vivant (non sérialisable) → il faudrait persister `(messageId, channelId, …)`, **re-fetch** les messages au boot et gérer ceux supprimés entre-temps, plus une **table dédiée** — qu'on vient justement de supprimer (clean cut de la migration). Trop pour une feature `priority: low`. +- **Juste-milieu écarté** : un drain best-effort au graceful shutdown ne couvrirait que les deploys planifiés (pas les crashes) et resterait limité par le délai de grâce + le rate limit → bénéfice marginal. + +À reconsidérer seulement si la création de fil devient critique (modération/traçabilité) ou si des pics + redémarrages fréquents rendent la perte visible. + +## #37 — multi-salons + +L'issue #37 (configurer plusieurs salons par serveur) dépendait de cette file : sans elle, surveiller plusieurs salons amplifierait les drops. La file en place, le multi-salons est livré en passant le champ de config `channel` (salon unique) à **`channels: ListOf`** : le service crée un fil si le message est posté dans **l'un** des salons surveillés, et toutes les créations passent par la file (donc partagent la même fenêtre de rate limit par serveur). + +## Impact sur le schéma + +Aucun changement de schéma de base nécessaire (file en mémoire). Depuis la v2.0.0, le module n'a plus de table dédiée : sa configuration vit dans le système générique (`GuildConfiguration`, blob JSON par serveur). Le multi-salons s'est donc fait au niveau du schéma de config du module (`channel` → `channels: ListOf`), sans migration de table. **Clean cut** : les configs `channel` (singulier) déjà enregistrées ne sont pas reprises — les serveurs concernés re-sélectionnent leurs salons via `/config thread-creator`. + +## Implémentation + +- `services/thread-creation-queue.ts` — `ThreadCreationQueue` : file FIFO par serveur, cadence ≤ 5 / 10 s, reprise par `setTimeout` quand la fenêtre est pleine, drain non réentrant (un seul `pump` par serveur). Erreur sur un job loggée sans bloquer la file. +- `services/thread-creator.service.ts` — `scheduleThreadForMessage` : teste l'appartenance du salon à `channels`, génère le nom du fil, puis enfile le job. +- Tests : `services/thread-creation-queue.test.ts` (FIFO sans drop sur plusieurs fenêtres, cadence ≤ 5/10 s, isolation par serveur, message de bienvenue) avec fake timers. diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..c909a20 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,15 @@ +{ + "name": "omnibot-docs", + "version": "1.0.0", + "private": true, + "description": "OmniBot documentation", + "type": "module", + "scripts": { + "dev": "vitepress dev", + "build": "vitepress build", + "preview": "vitepress preview" + }, + "dependencies": { + "vitepress": "^1.6.4" + } +} diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml new file mode 100644 index 0000000..81e5cc9 --- /dev/null +++ b/docs/pnpm-lock.yaml @@ -0,0 +1,1620 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + vitepress: + specifier: ^1.6.4 + version: 1.6.4(@algolia/client-search@5.54.0)(postcss@8.5.15)(search-insights@2.17.3) + +packages: + + '@algolia/abtesting@1.20.0': + resolution: {integrity: sha512-5CqkS592H3+24b6H6CQ2RVpphdmAuIElZzv0Hngqo/ZEZpUZJ+KGLcueBhx33fv2wYBXyuuvskG5aQ7Ti+lR0g==} + engines: {node: '>= 14.0.0'} + + '@algolia/autocomplete-core@1.17.7': + resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==} + + '@algolia/autocomplete-plugin-algolia-insights@1.17.7': + resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==} + peerDependencies: + search-insights: '>= 1 < 3' + + '@algolia/autocomplete-preset-algolia@1.17.7': + resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + + '@algolia/autocomplete-shared@1.17.7': + resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + + '@algolia/client-abtesting@5.54.0': + resolution: {integrity: sha512-IXnH1x3DBsPQA4/FRO0Pvkfy79tKy5Qr+ugAV9jdcGkpzHc476D0WV1MFJ+pZxtbts0xh2JqzUVmYEqA6LkOpA==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-analytics@5.54.0': + resolution: {integrity: sha512-pBpRqm1wpE0GnGy2rNLk9rjDn0Le4iywNRtnAWblLeqfjxpWKg8lWnk7nmSoTShFO31sz2jatXXzxK2lz8ipbA==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-common@5.54.0': + resolution: {integrity: sha512-WbuwRUlFvSOsuxqTDjSSmgusuF5KFt+oFPzobvPDvodra6EWnVwUXjz0elkNSsnsIlZGtcXlX3LhxkO7rF90jw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-insights@5.54.0': + resolution: {integrity: sha512-/HNLVi3kPI+JhO59WbglLjPM2c4uECU+x4gk1iADseKtE5eYqJ/RJ+FIwM8xzPFKhFJaw+8hVq4lkd0nn8HDDg==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-personalization@5.54.0': + resolution: {integrity: sha512-6TolyyDRumIKeLGBGSFAZsSIJ8hrm6NFCGR1jO7pQTiOtSWgAIxcFE5/JRpZ3g+unG4OkNOFy+I0dUEquIDbig==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-query-suggestions@5.54.0': + resolution: {integrity: sha512-AxW2MLBhjBtGX5kIZrVLO2SP2vRkZxJw5qHGxnQJfLcYhA04mFNP0fWRtHshlcVnDk9M8L9lwfr2lGpf3Er+hw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-search@5.54.0': + resolution: {integrity: sha512-ngdgVGp05lJzUyA+sUzr0MDZ7AMtANcJpwIzq4ZsfpZL5B3S7A4XYfMcU2sECZc3bx3ysOhYcdbbaTjc3ve0WQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/ingestion@1.54.0': + resolution: {integrity: sha512-hee59Z7FgZ6/13FYL05ANPwRJY1pfvIlrwC8eBZYdiRFXTJVvf94IyTWOxLqRVpbseDP6eQQTW+PT7/DxTZIng==} + engines: {node: '>= 14.0.0'} + + '@algolia/monitoring@1.54.0': + resolution: {integrity: sha512-diCjZVbIO7Pzw98tEKqLWIAgmQBI3Zt1sHsXyAPNGZgn32derpIXTnjjpJbZl+uAhSSznd6SfxFGdC9uYdN1TA==} + engines: {node: '>= 14.0.0'} + + '@algolia/recommend@5.54.0': + resolution: {integrity: sha512-6zeslypRAGWDgVJEJYAPuqmyquHvnw4MQwG+XXdrw5dTNDjXYIcCJdQQcCY06xPF9tUvmzy/1vHiH9QxhgwuOQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-browser-xhr@5.54.0': + resolution: {integrity: sha512-iHZax214LPXd7XizQ4BNnTsegl8f3IeKm8JcrmSNZ/5x1rZ5xLkbG/anltAWtLpoRNnfpr4Z80YdYeVVPpx6wQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-fetch@5.54.0': + resolution: {integrity: sha512-YKtuG5YwPxZ+kkfd4HmUO7Z9aICPUSMlHslzKTmtMMhxGnetxEqGj9T/v2r/PdcuOUC5oW0CHe8akJk8cpS3gQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-node-http@5.54.0': + resolution: {integrity: sha512-zyZDJ4WS5TnjZZ5pqywTBFO9olW7QMtY2kf2dbLnu+UTzfc9ri/HGf27jRN2NTbX9FcRPxSqPqzUhF/BZIx0VA==} + engines: {node: '>= 14.0.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@docsearch/css@3.8.2': + resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==} + + '@docsearch/js@3.8.2': + resolution: {integrity: sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==} + + '@docsearch/react@3.8.2': + resolution: {integrity: sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==} + peerDependencies: + '@types/react': '>= 16.8.0 < 19.0.0' + react: '>= 16.8.0 < 19.0.0' + react-dom: '>= 16.8.0 < 19.0.0' + search-insights: '>= 1 < 3' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@iconify-json/simple-icons@1.2.86': + resolution: {integrity: sha512-t3jck5qPQuK1qy+bRn9eCoDQhIB7XSazKz1Fjp8hcan3XOAsTI5Mq/s3F0ekOKSvMQqkVORYK6ns6o6T9f5EMA==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@rollup/rollup-android-arm-eabi@4.61.1': + resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.61.1': + resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.61.1': + resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.61.1': + resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.61.1': + resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.61.1': + resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.61.1': + resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.61.1': + resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.61.1': + resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.61.1': + resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.61.1': + resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.61.1': + resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.61.1': + resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.61.1': + resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.61.1': + resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.61.1': + resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.61.1': + resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.61.1': + resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.61.1': + resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.61.1': + resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.61.1': + resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} + cpu: [x64] + os: [win32] + + '@shikijs/core@2.5.0': + resolution: {integrity: sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==} + + '@shikijs/engine-javascript@2.5.0': + resolution: {integrity: sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==} + + '@shikijs/engine-oniguruma@2.5.0': + resolution: {integrity: sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==} + + '@shikijs/langs@2.5.0': + resolution: {integrity: sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==} + + '@shikijs/themes@2.5.0': + resolution: {integrity: sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==} + + '@shikijs/transformers@2.5.0': + resolution: {integrity: sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==} + + '@shikijs/types@2.5.0': + resolution: {integrity: sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + + '@vitejs/plugin-vue@5.2.4': + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@vue/compiler-core@3.5.38': + resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} + + '@vue/compiler-dom@3.5.38': + resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} + + '@vue/compiler-sfc@3.5.38': + resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} + + '@vue/compiler-ssr@3.5.38': + resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} + + '@vue/devtools-api@7.7.9': + resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + + '@vue/devtools-kit@7.7.9': + resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + + '@vue/devtools-shared@7.7.9': + resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + + '@vue/reactivity@3.5.38': + resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} + + '@vue/runtime-core@3.5.38': + resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} + + '@vue/runtime-dom@3.5.38': + resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} + + '@vue/server-renderer@3.5.38': + resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} + peerDependencies: + vue: 3.5.38 + + '@vue/shared@3.5.38': + resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} + + '@vueuse/core@12.8.2': + resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} + + '@vueuse/integrations@12.8.2': + resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@12.8.2': + resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} + + '@vueuse/shared@12.8.2': + resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} + + algoliasearch@5.54.0: + resolution: {integrity: sha512-APAX4ajIOgsmYoUlGe++oNZkSTBgmXYM4maHC0OxC+Yo7xkaKQElV0ATZYCZA7jzrSJX1OBiqEs7mk+ZxXgYqA==} + engines: {node: '>= 14.0.0'} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + focus-trap@7.8.0: + resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + minisearch@7.2.0: + resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + oniguruma-to-es@3.1.1: + resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + preact@10.29.2: + resolution: {integrity: sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rollup@4.61.1: + resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + search-insights@2.17.3: + resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} + + shiki@2.5.0: + resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitepress@1.6.4: + resolution: {integrity: sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==} + hasBin: true + peerDependencies: + markdown-it-mathjax3: ^4 + postcss: ^8 + peerDependenciesMeta: + markdown-it-mathjax3: + optional: true + postcss: + optional: true + + vue@3.5.38: + resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@algolia/abtesting@1.20.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3)': + dependencies: + '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + - search-insights + + '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3)': + dependencies: + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + search-insights: 2.17.3 + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + + '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)': + dependencies: + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + '@algolia/client-search': 5.54.0 + algoliasearch: 5.54.0 + + '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)': + dependencies: + '@algolia/client-search': 5.54.0 + algoliasearch: 5.54.0 + + '@algolia/client-abtesting@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-analytics@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-common@5.54.0': {} + + '@algolia/client-insights@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-personalization@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-query-suggestions@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-search@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/ingestion@1.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/monitoring@1.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/recommend@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/requester-browser-xhr@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + + '@algolia/requester-fetch@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + + '@algolia/requester-node-http@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@docsearch/css@3.8.2': {} + + '@docsearch/js@3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3)': + dependencies: + '@docsearch/react': 3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3) + preact: 10.29.2 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/react' + - react + - react-dom + - search-insights + + '@docsearch/react@3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3)': + dependencies: + '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3) + '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + '@docsearch/css': 3.8.2 + algoliasearch: 5.54.0 + optionalDependencies: + search-insights: 2.17.3 + transitivePeerDependencies: + - '@algolia/client-search' + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@iconify-json/simple-icons@1.2.86': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@rollup/rollup-android-arm-eabi@4.61.1': + optional: true + + '@rollup/rollup-android-arm64@4.61.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.61.1': + optional: true + + '@rollup/rollup-darwin-x64@4.61.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.61.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.61.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.61.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.61.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.61.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.61.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.61.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.61.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.61.1': + optional: true + + '@shikijs/core@2.5.0': + dependencies: + '@shikijs/engine-javascript': 2.5.0 + '@shikijs/engine-oniguruma': 2.5.0 + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 3.1.1 + + '@shikijs/engine-oniguruma@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + + '@shikijs/themes@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + + '@shikijs/transformers@2.5.0': + dependencies: + '@shikijs/core': 2.5.0 + '@shikijs/types': 2.5.0 + + '@shikijs/types@2.5.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdurl@2.0.0': {} + + '@types/unist@3.0.3': {} + + '@types/web-bluetooth@0.0.21': {} + + '@ungap/structured-clone@1.3.1': {} + + '@vitejs/plugin-vue@5.2.4(vite@5.4.21)(vue@3.5.38)': + dependencies: + vite: 5.4.21 + vue: 3.5.38 + + '@vue/compiler-core@3.5.38': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.38 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.38': + dependencies: + '@vue/compiler-core': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/compiler-sfc@3.5.38': + dependencies: + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.38 + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.15 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.38': + dependencies: + '@vue/compiler-dom': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/devtools-api@7.7.9': + dependencies: + '@vue/devtools-kit': 7.7.9 + + '@vue/devtools-kit@7.7.9': + dependencies: + '@vue/devtools-shared': 7.7.9 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + + '@vue/devtools-shared@7.7.9': + dependencies: + rfdc: 1.4.1 + + '@vue/reactivity@3.5.38': + dependencies: + '@vue/shared': 3.5.38 + + '@vue/runtime-core@3.5.38': + dependencies: + '@vue/reactivity': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/runtime-dom@3.5.38': + dependencies: + '@vue/reactivity': 3.5.38 + '@vue/runtime-core': 3.5.38 + '@vue/shared': 3.5.38 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.38(vue@3.5.38)': + dependencies: + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + vue: 3.5.38 + + '@vue/shared@3.5.38': {} + + '@vueuse/core@12.8.2': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 12.8.2 + '@vueuse/shared': 12.8.2 + vue: 3.5.38 + transitivePeerDependencies: + - typescript + + '@vueuse/integrations@12.8.2(focus-trap@7.8.0)': + dependencies: + '@vueuse/core': 12.8.2 + '@vueuse/shared': 12.8.2 + vue: 3.5.38 + optionalDependencies: + focus-trap: 7.8.0 + transitivePeerDependencies: + - typescript + + '@vueuse/metadata@12.8.2': {} + + '@vueuse/shared@12.8.2': + dependencies: + vue: 3.5.38 + transitivePeerDependencies: + - typescript + + algoliasearch@5.54.0: + dependencies: + '@algolia/abtesting': 1.20.0 + '@algolia/client-abtesting': 5.54.0 + '@algolia/client-analytics': 5.54.0 + '@algolia/client-common': 5.54.0 + '@algolia/client-insights': 5.54.0 + '@algolia/client-personalization': 5.54.0 + '@algolia/client-query-suggestions': 5.54.0 + '@algolia/client-search': 5.54.0 + '@algolia/ingestion': 1.54.0 + '@algolia/monitoring': 1.54.0 + '@algolia/recommend': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + birpc@2.9.0: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + comma-separated-tokens@2.0.3: {} + + copy-anything@4.0.5: + dependencies: + is-what: 5.5.0 + + csstype@3.2.3: {} + + dequal@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + emoji-regex-xs@1.0.0: {} + + entities@7.0.1: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + estree-walker@2.0.2: {} + + focus-trap@7.8.0: + dependencies: + tabbable: 6.4.0 + + fsevents@2.3.3: + optional: true + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hookable@5.5.3: {} + + html-void-elements@3.0.0: {} + + is-what@5.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mark.js@8.11.1: {} + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-encode@2.0.1: {} + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + minisearch@7.2.0: {} + + mitt@3.0.1: {} + + nanoid@3.3.12: {} + + oniguruma-to-es@3.1.1: + dependencies: + emoji-regex-xs: 1.0.0 + regex: 6.1.0 + regex-recursion: 6.0.2 + + perfect-debounce@1.0.0: {} + + picocolors@1.1.1: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + preact@10.29.2: {} + + property-information@7.2.0: {} + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rfdc@1.4.1: {} + + rollup@4.61.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.61.1 + '@rollup/rollup-android-arm64': 4.61.1 + '@rollup/rollup-darwin-arm64': 4.61.1 + '@rollup/rollup-darwin-x64': 4.61.1 + '@rollup/rollup-freebsd-arm64': 4.61.1 + '@rollup/rollup-freebsd-x64': 4.61.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 + '@rollup/rollup-linux-arm-musleabihf': 4.61.1 + '@rollup/rollup-linux-arm64-gnu': 4.61.1 + '@rollup/rollup-linux-arm64-musl': 4.61.1 + '@rollup/rollup-linux-loong64-gnu': 4.61.1 + '@rollup/rollup-linux-loong64-musl': 4.61.1 + '@rollup/rollup-linux-ppc64-gnu': 4.61.1 + '@rollup/rollup-linux-ppc64-musl': 4.61.1 + '@rollup/rollup-linux-riscv64-gnu': 4.61.1 + '@rollup/rollup-linux-riscv64-musl': 4.61.1 + '@rollup/rollup-linux-s390x-gnu': 4.61.1 + '@rollup/rollup-linux-x64-gnu': 4.61.1 + '@rollup/rollup-linux-x64-musl': 4.61.1 + '@rollup/rollup-openbsd-x64': 4.61.1 + '@rollup/rollup-openharmony-arm64': 4.61.1 + '@rollup/rollup-win32-arm64-msvc': 4.61.1 + '@rollup/rollup-win32-ia32-msvc': 4.61.1 + '@rollup/rollup-win32-x64-gnu': 4.61.1 + '@rollup/rollup-win32-x64-msvc': 4.61.1 + fsevents: 2.3.3 + + search-insights@2.17.3: {} + + shiki@2.5.0: + dependencies: + '@shikijs/core': 2.5.0 + '@shikijs/engine-javascript': 2.5.0 + '@shikijs/engine-oniguruma': 2.5.0 + '@shikijs/langs': 2.5.0 + '@shikijs/themes': 2.5.0 + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + source-map-js@1.2.1: {} + + space-separated-tokens@2.0.2: {} + + speakingurl@14.0.1: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + superjson@2.2.6: + dependencies: + copy-anything: 4.0.5 + + tabbable@6.4.0: {} + + trim-lines@3.0.1: {} + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@5.4.21: + dependencies: + esbuild: 0.21.5 + postcss: 8.5.15 + rollup: 4.61.1 + optionalDependencies: + fsevents: 2.3.3 + + vitepress@1.6.4(@algolia/client-search@5.54.0)(postcss@8.5.15)(search-insights@2.17.3): + dependencies: + '@docsearch/css': 3.8.2 + '@docsearch/js': 3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3) + '@iconify-json/simple-icons': 1.2.86 + '@shikijs/core': 2.5.0 + '@shikijs/transformers': 2.5.0 + '@shikijs/types': 2.5.0 + '@types/markdown-it': 14.1.2 + '@vitejs/plugin-vue': 5.2.4(vite@5.4.21)(vue@3.5.38) + '@vue/devtools-api': 7.7.9 + '@vue/shared': 3.5.38 + '@vueuse/core': 12.8.2 + '@vueuse/integrations': 12.8.2(focus-trap@7.8.0) + focus-trap: 7.8.0 + mark.js: 8.11.1 + minisearch: 7.2.0 + shiki: 2.5.0 + vite: 5.4.21 + vue: 3.5.38 + optionalDependencies: + postcss: 8.5.15 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/node' + - '@types/react' + - async-validator + - axios + - change-case + - drauu + - fuse.js + - idb-keyval + - jwt-decode + - less + - lightningcss + - nprogress + - qrcode + - react + - react-dom + - sass + - sass-embedded + - search-insights + - sortablejs + - stylus + - sugarss + - terser + - typescript + - universal-cookie + + vue@3.5.38: + dependencies: + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-sfc': 3.5.38 + '@vue/runtime-dom': 3.5.38 + '@vue/server-renderer': 3.5.38(vue@3.5.38) + '@vue/shared': 3.5.38 + + zwitch@2.0.4: {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c93c6c7..47800b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,16 +56,115 @@ importers: specifier: ^4.1.8 version: 4.1.8(@types/node@24.13.2)(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.4)(yaml@2.9.0)) + docs: + dependencies: + vitepress: + specifier: ^1.6.4 + version: 1.6.4(@algolia/client-search@5.54.0)(@types/node@24.13.2)(lightningcss@1.32.0)(postcss@8.5.15)(search-insights@2.17.3)(typescript@5.9.3) + packages: + '@algolia/abtesting@1.20.0': + resolution: {integrity: sha512-5CqkS592H3+24b6H6CQ2RVpphdmAuIElZzv0Hngqo/ZEZpUZJ+KGLcueBhx33fv2wYBXyuuvskG5aQ7Ti+lR0g==} + engines: {node: '>= 14.0.0'} + + '@algolia/autocomplete-core@1.17.7': + resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==} + + '@algolia/autocomplete-plugin-algolia-insights@1.17.7': + resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==} + peerDependencies: + search-insights: '>= 1 < 3' + + '@algolia/autocomplete-preset-algolia@1.17.7': + resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + + '@algolia/autocomplete-shared@1.17.7': + resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + + '@algolia/client-abtesting@5.54.0': + resolution: {integrity: sha512-IXnH1x3DBsPQA4/FRO0Pvkfy79tKy5Qr+ugAV9jdcGkpzHc476D0WV1MFJ+pZxtbts0xh2JqzUVmYEqA6LkOpA==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-analytics@5.54.0': + resolution: {integrity: sha512-pBpRqm1wpE0GnGy2rNLk9rjDn0Le4iywNRtnAWblLeqfjxpWKg8lWnk7nmSoTShFO31sz2jatXXzxK2lz8ipbA==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-common@5.54.0': + resolution: {integrity: sha512-WbuwRUlFvSOsuxqTDjSSmgusuF5KFt+oFPzobvPDvodra6EWnVwUXjz0elkNSsnsIlZGtcXlX3LhxkO7rF90jw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-insights@5.54.0': + resolution: {integrity: sha512-/HNLVi3kPI+JhO59WbglLjPM2c4uECU+x4gk1iADseKtE5eYqJ/RJ+FIwM8xzPFKhFJaw+8hVq4lkd0nn8HDDg==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-personalization@5.54.0': + resolution: {integrity: sha512-6TolyyDRumIKeLGBGSFAZsSIJ8hrm6NFCGR1jO7pQTiOtSWgAIxcFE5/JRpZ3g+unG4OkNOFy+I0dUEquIDbig==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-query-suggestions@5.54.0': + resolution: {integrity: sha512-AxW2MLBhjBtGX5kIZrVLO2SP2vRkZxJw5qHGxnQJfLcYhA04mFNP0fWRtHshlcVnDk9M8L9lwfr2lGpf3Er+hw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-search@5.54.0': + resolution: {integrity: sha512-ngdgVGp05lJzUyA+sUzr0MDZ7AMtANcJpwIzq4ZsfpZL5B3S7A4XYfMcU2sECZc3bx3ysOhYcdbbaTjc3ve0WQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/ingestion@1.54.0': + resolution: {integrity: sha512-hee59Z7FgZ6/13FYL05ANPwRJY1pfvIlrwC8eBZYdiRFXTJVvf94IyTWOxLqRVpbseDP6eQQTW+PT7/DxTZIng==} + engines: {node: '>= 14.0.0'} + + '@algolia/monitoring@1.54.0': + resolution: {integrity: sha512-diCjZVbIO7Pzw98tEKqLWIAgmQBI3Zt1sHsXyAPNGZgn32derpIXTnjjpJbZl+uAhSSznd6SfxFGdC9uYdN1TA==} + engines: {node: '>= 14.0.0'} + + '@algolia/recommend@5.54.0': + resolution: {integrity: sha512-6zeslypRAGWDgVJEJYAPuqmyquHvnw4MQwG+XXdrw5dTNDjXYIcCJdQQcCY06xPF9tUvmzy/1vHiH9QxhgwuOQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-browser-xhr@5.54.0': + resolution: {integrity: sha512-iHZax214LPXd7XizQ4BNnTsegl8f3IeKm8JcrmSNZ/5x1rZ5xLkbG/anltAWtLpoRNnfpr4Z80YdYeVVPpx6wQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-fetch@5.54.0': + resolution: {integrity: sha512-YKtuG5YwPxZ+kkfd4HmUO7Z9aICPUSMlHslzKTmtMMhxGnetxEqGj9T/v2r/PdcuOUC5oW0CHe8akJk8cpS3gQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-node-http@5.54.0': + resolution: {integrity: sha512-zyZDJ4WS5TnjZZ5pqywTBFO9olW7QMtY2kf2dbLnu+UTzfc9ri/HGf27jRN2NTbX9FcRPxSqPqzUhF/BZIx0VA==} + engines: {node: '>= 14.0.0'} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + '@commitlint/cli@21.0.2': resolution: {integrity: sha512-YMmfLbqBg+ZRvvmPhc+cilSQFrh/AgzVgCT1U/OifmUZEwPbvCtA8rN//YNaF9d5eoZphxVMGYtmwA2QgQORgg==} engines: {node: '>=22.12.0'} @@ -175,6 +274,29 @@ packages: resolution: {integrity: sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==} engines: {node: '>=16.11.0'} + '@docsearch/css@3.8.2': + resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==} + + '@docsearch/js@3.8.2': + resolution: {integrity: sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==} + + '@docsearch/react@3.8.2': + resolution: {integrity: sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==} + peerDependencies: + '@types/react': '>= 16.8.0 < 19.0.0' + react: '>= 16.8.0 < 19.0.0' + react-dom: '>= 16.8.0 < 19.0.0' + search-insights: '>= 1 < 3' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -184,102 +306,204 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.28.1': resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.28.1': resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.28.1': resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.28.1': resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.28.1': resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.28.1': resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.28.1': resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.28.1': resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.28.1': resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.28.1': resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.28.1': resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.28.1': resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.28.1': resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.28.1': resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.28.1': resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.28.1': resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} @@ -292,6 +516,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.28.1': resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} @@ -304,6 +534,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.28.1': resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} @@ -316,30 +552,60 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.28.1': resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.28.1': resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.28.1': resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.28.1': resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@iconify-json/simple-icons@1.2.86': + resolution: {integrity: sha512-t3jck5qPQuK1qy+bRn9eCoDQhIB7XSazKz1Fjp8hcan3XOAsTI5Mq/s3F0ekOKSvMQqkVORYK6ns6o6T9f5EMA==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -727,6 +993,144 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/rollup-android-arm-eabi@4.61.1': + resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.61.1': + resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.61.1': + resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.61.1': + resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.61.1': + resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.61.1': + resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.61.1': + resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.61.1': + resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.61.1': + resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.61.1': + resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.61.1': + resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.61.1': + resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.61.1': + resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.61.1': + resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.61.1': + resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.61.1': + resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.61.1': + resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.61.1': + resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.61.1': + resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.61.1': + resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.61.1': + resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} + cpu: [x64] + os: [win32] + '@sapphire/async-queue@1.5.5': resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -743,6 +1147,30 @@ packages: resolution: {integrity: sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@shikijs/core@2.5.0': + resolution: {integrity: sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==} + + '@shikijs/engine-javascript@2.5.0': + resolution: {integrity: sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==} + + '@shikijs/engine-oniguruma@2.5.0': + resolution: {integrity: sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==} + + '@shikijs/langs@2.5.0': + resolution: {integrity: sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==} + + '@shikijs/themes@2.5.0': + resolution: {integrity: sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==} + + '@shikijs/transformers@2.5.0': + resolution: {integrity: sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==} + + '@shikijs/types@2.5.0': + resolution: {integrity: sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@simple-libs/child-process-utils@1.0.2': resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} engines: {node: '>=18'} @@ -766,12 +1194,43 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/node@24.13.2': resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + + '@vitejs/plugin-vue@5.2.4': + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + '@vitest/expect@4.1.8': resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} @@ -805,9 +1264,101 @@ packages: resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@vue/compiler-core@3.5.38': + resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} + + '@vue/compiler-dom@3.5.38': + resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} + + '@vue/compiler-sfc@3.5.38': + resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} + + '@vue/compiler-ssr@3.5.38': + resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} + + '@vue/devtools-api@7.7.9': + resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + + '@vue/devtools-kit@7.7.9': + resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + + '@vue/devtools-shared@7.7.9': + resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + + '@vue/reactivity@3.5.38': + resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} + + '@vue/runtime-core@3.5.38': + resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} + + '@vue/runtime-dom@3.5.38': + resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} + + '@vue/server-renderer@3.5.38': + resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} + peerDependencies: + vue: 3.5.38 + + '@vue/shared@3.5.38': + resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} + + '@vueuse/core@12.8.2': + resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} + + '@vueuse/integrations@12.8.2': + resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@12.8.2': + resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} + + '@vueuse/shared@12.8.2': + resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} + ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + algoliasearch@5.54.0: + resolution: {integrity: sha512-APAX4ajIOgsmYoUlGe++oNZkSTBgmXYM4maHC0OxC+Yo7xkaKQElV0ATZYCZA7jzrSJX1OBiqEs7mk+ZxXgYqA==} + engines: {node: '>= 14.0.0'} + ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} @@ -830,6 +1381,9 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + c12@3.1.0: resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} peerDependencies: @@ -842,10 +1396,19 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -863,6 +1426,9 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} @@ -889,6 +1455,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} + cosmiconfig-typescript-loader@6.3.0: resolution: {integrity: sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==} engines: {node: '>=v18'} @@ -906,6 +1476,9 @@ packages: typescript: optional: true + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} @@ -916,6 +1489,10 @@ packages: defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -923,6 +1500,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + discord-api-types@0.38.47: resolution: {integrity: sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==} @@ -941,6 +1521,9 @@ packages: effect@3.21.0: resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -951,6 +1534,10 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -964,6 +1551,11 @@ packages: es-toolkit@1.46.1: resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -973,6 +1565,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -1008,6 +1603,9 @@ packages: picomatch: optional: true + focus-trap@7.8.0: + resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1034,9 +1632,21 @@ packages: resolution: {integrity: sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==} engines: {node: '>=20'} + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -1056,6 +1666,10 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -1220,13 +1834,40 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minisearch@7.2.0: + resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1254,6 +1895,9 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + oniguruma-to-es@3.1.1: + resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==} + oxfmt@0.54.0: resolution: {integrity: sha512-DjnMwn7smSLF+Mc2+pRItnuPftm/dkUFpY/d4+33y9TfKrsHZo8GLhmUg9BrOIUEy94Rlom1Q11N6vuhE+e0oQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1322,6 +1966,9 @@ packages: resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} + preact@10.29.2: + resolution: {integrity: sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==} + prisma@6.19.3: resolution: {integrity: sha512-++ZJ0ijLrDJF6hNB4t4uxg2br3fC4H9Yc9tcbjr2fcNFP3rh/SBNrAgjhsqBU4Ght8JPrVofG/ZkXfnSfnYsFg==} engines: {node: '>=18.18'} @@ -1335,6 +1982,9 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -1358,6 +2008,15 @@ packages: real-require@1.0.0: resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -1370,15 +2029,26 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rolldown@1.0.3: resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rollup@4.61.1: + resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} + search-insights@2.17.3: + resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} + secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} @@ -1387,6 +2057,9 @@ packages: engines: {node: '>=10'} hasBin: true + shiki@2.5.0: + resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1397,6 +2070,13 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -1411,6 +2091,9 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@7.2.0: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} @@ -1419,6 +2102,13 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + thread-stream@4.2.0: resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} engines: {node: '>=20'} @@ -1442,6 +2132,9 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} @@ -1465,6 +2158,58 @@ packages: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + vite@8.0.16: resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1508,6 +2253,18 @@ packages: yaml: optional: true + vitepress@1.6.4: + resolution: {integrity: sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==} + hasBin: true + peerDependencies: + markdown-it-mathjax3: ^4 + postcss: ^8 + peerDependenciesMeta: + markdown-it-mathjax3: + optional: true + postcss: + optional: true + vitest@4.1.8: resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -1549,6 +2306,14 @@ packages: jsdom: optional: true + vue@3.5.38: + resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -1590,16 +2355,144 @@ packages: resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} engines: {node: ^20.19.0 || ^22.12.0 || >=23} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: + '@algolia/abtesting@1.20.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3)': + dependencies: + '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + - search-insights + + '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3)': + dependencies: + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + search-insights: 2.17.3 + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + + '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)': + dependencies: + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + '@algolia/client-search': 5.54.0 + algoliasearch: 5.54.0 + + '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)': + dependencies: + '@algolia/client-search': 5.54.0 + algoliasearch: 5.54.0 + + '@algolia/client-abtesting@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-analytics@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-common@5.54.0': {} + + '@algolia/client-insights@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-personalization@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-query-suggestions@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/client-search@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/ingestion@1.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/monitoring@1.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/recommend@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + + '@algolia/requester-browser-xhr@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + + '@algolia/requester-fetch@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + + '@algolia/requester-node-http@5.54.0': + dependencies: + '@algolia/client-common': 5.54.0 + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/helper-string-parser@7.29.7': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@commitlint/cli@21.0.2(@types/node@24.13.2)(conventional-commits-parser@6.4.0)(typescript@5.9.3)': dependencies: '@commitlint/format': 21.0.1 @@ -1765,6 +2658,30 @@ snapshots: - bufferutil - utf-8-validate + '@docsearch/css@3.8.2': {} + + '@docsearch/js@3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3)': + dependencies: + '@docsearch/react': 3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3) + preact: 10.29.2 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/react' + - react + - react-dom + - search-insights + + '@docsearch/react@3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3)': + dependencies: + '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3) + '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) + '@docsearch/css': 3.8.2 + algoliasearch: 5.54.0 + optionalDependencies: + search-insights: 2.17.3 + transitivePeerDependencies: + - '@algolia/client-search' + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -1781,84 +2698,159 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.21.5': + optional: true + '@esbuild/aix-ppc64@0.28.1': optional: true + '@esbuild/android-arm64@0.21.5': + optional: true + '@esbuild/android-arm64@0.28.1': optional: true + '@esbuild/android-arm@0.21.5': + optional: true + '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.28.1': + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.21.5': optional: true '@esbuild/darwin-arm64@0.28.1': optional: true + '@esbuild/darwin-x64@0.21.5': + optional: true + '@esbuild/darwin-x64@0.28.1': optional: true + '@esbuild/freebsd-arm64@0.21.5': + optional: true + '@esbuild/freebsd-arm64@0.28.1': optional: true + '@esbuild/freebsd-x64@0.21.5': + optional: true + '@esbuild/freebsd-x64@0.28.1': optional: true + '@esbuild/linux-arm64@0.21.5': + optional: true + '@esbuild/linux-arm64@0.28.1': optional: true + '@esbuild/linux-arm@0.21.5': + optional: true + '@esbuild/linux-arm@0.28.1': optional: true + '@esbuild/linux-ia32@0.21.5': + optional: true + '@esbuild/linux-ia32@0.28.1': optional: true + '@esbuild/linux-loong64@0.21.5': + optional: true + '@esbuild/linux-loong64@0.28.1': optional: true + '@esbuild/linux-mips64el@0.21.5': + optional: true + '@esbuild/linux-mips64el@0.28.1': optional: true + '@esbuild/linux-ppc64@0.21.5': + optional: true + '@esbuild/linux-ppc64@0.28.1': optional: true + '@esbuild/linux-riscv64@0.21.5': + optional: true + '@esbuild/linux-riscv64@0.28.1': optional: true + '@esbuild/linux-s390x@0.21.5': + optional: true + '@esbuild/linux-s390x@0.28.1': optional: true + '@esbuild/linux-x64@0.21.5': + optional: true + '@esbuild/linux-x64@0.28.1': optional: true '@esbuild/netbsd-arm64@0.28.1': optional: true + '@esbuild/netbsd-x64@0.21.5': + optional: true + '@esbuild/netbsd-x64@0.28.1': optional: true '@esbuild/openbsd-arm64@0.28.1': optional: true + '@esbuild/openbsd-x64@0.21.5': + optional: true + '@esbuild/openbsd-x64@0.28.1': optional: true '@esbuild/openharmony-arm64@0.28.1': optional: true + '@esbuild/sunos-x64@0.21.5': + optional: true + '@esbuild/sunos-x64@0.28.1': optional: true + '@esbuild/win32-arm64@0.21.5': + optional: true + '@esbuild/win32-arm64@0.28.1': optional: true + '@esbuild/win32-ia32@0.21.5': + optional: true + '@esbuild/win32-ia32@0.28.1': optional: true + '@esbuild/win32-x64@0.21.5': + optional: true + '@esbuild/win32-x64@0.28.1': optional: true + '@iconify-json/simple-icons@1.2.86': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': @@ -2072,6 +3064,81 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@rollup/rollup-android-arm-eabi@4.61.1': + optional: true + + '@rollup/rollup-android-arm64@4.61.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.61.1': + optional: true + + '@rollup/rollup-darwin-x64@4.61.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.61.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.61.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.61.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.61.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.61.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.61.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.61.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.61.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.61.1': + optional: true + '@sapphire/async-queue@1.5.5': {} '@sapphire/shapeshift@4.0.0': @@ -2083,6 +3150,46 @@ snapshots: '@sapphire/snowflake@3.5.5': {} + '@shikijs/core@2.5.0': + dependencies: + '@shikijs/engine-javascript': 2.5.0 + '@shikijs/engine-oniguruma': 2.5.0 + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 3.1.1 + + '@shikijs/engine-oniguruma@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + + '@shikijs/themes@2.5.0': + dependencies: + '@shikijs/types': 2.5.0 + + '@shikijs/transformers@2.5.0': + dependencies: + '@shikijs/core': 2.5.0 + '@shikijs/types': 2.5.0 + + '@shikijs/types@2.5.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@simple-libs/child-process-utils@1.0.2': dependencies: '@simple-libs/stream-utils': 1.2.0 @@ -2105,14 +3212,42 @@ snapshots: '@types/estree@1.0.9': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdurl@2.0.0': {} + '@types/node@24.13.2': dependencies: undici-types: 7.18.2 + '@types/unist@3.0.3': {} + + '@types/web-bluetooth@0.0.21': {} + '@types/ws@8.18.1': dependencies: '@types/node': 24.13.2 + '@ungap/structured-clone@1.3.1': {} + + '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@24.13.2)(lightningcss@1.32.0))(vue@3.5.38(typescript@5.9.3))': + dependencies: + vite: 5.4.21(@types/node@24.13.2)(lightningcss@1.32.0) + vue: 3.5.38(typescript@5.9.3) + '@vitest/expect@4.1.8': dependencies: '@standard-schema/spec': 1.1.0 @@ -2156,6 +3291,105 @@ snapshots: '@vladfrangu/async_event_emitter@2.4.7': {} + '@vue/compiler-core@3.5.38': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.38 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.38': + dependencies: + '@vue/compiler-core': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/compiler-sfc@3.5.38': + dependencies: + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.38 + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.15 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.38': + dependencies: + '@vue/compiler-dom': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/devtools-api@7.7.9': + dependencies: + '@vue/devtools-kit': 7.7.9 + + '@vue/devtools-kit@7.7.9': + dependencies: + '@vue/devtools-shared': 7.7.9 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + + '@vue/devtools-shared@7.7.9': + dependencies: + rfdc: 1.4.1 + + '@vue/reactivity@3.5.38': + dependencies: + '@vue/shared': 3.5.38 + + '@vue/runtime-core@3.5.38': + dependencies: + '@vue/reactivity': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/runtime-dom@3.5.38': + dependencies: + '@vue/reactivity': 3.5.38 + '@vue/runtime-core': 3.5.38 + '@vue/shared': 3.5.38 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@5.9.3))': + dependencies: + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + vue: 3.5.38(typescript@5.9.3) + + '@vue/shared@3.5.38': {} + + '@vueuse/core@12.8.2(typescript@5.9.3)': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 12.8.2 + '@vueuse/shared': 12.8.2(typescript@5.9.3) + vue: 3.5.38(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@vueuse/integrations@12.8.2(focus-trap@7.8.0)(typescript@5.9.3)': + dependencies: + '@vueuse/core': 12.8.2(typescript@5.9.3) + '@vueuse/shared': 12.8.2(typescript@5.9.3) + vue: 3.5.38(typescript@5.9.3) + optionalDependencies: + focus-trap: 7.8.0 + transitivePeerDependencies: + - typescript + + '@vueuse/metadata@12.8.2': {} + + '@vueuse/shared@12.8.2(typescript@5.9.3)': + dependencies: + vue: 3.5.38(typescript@5.9.3) + transitivePeerDependencies: + - typescript + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 @@ -2163,6 +3397,23 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + algoliasearch@5.54.0: + dependencies: + '@algolia/abtesting': 1.20.0 + '@algolia/client-abtesting': 5.54.0 + '@algolia/client-analytics': 5.54.0 + '@algolia/client-common': 5.54.0 + '@algolia/client-insights': 5.54.0 + '@algolia/client-personalization': 5.54.0 + '@algolia/client-query-suggestions': 5.54.0 + '@algolia/client-search': 5.54.0 + '@algolia/ingestion': 1.54.0 + '@algolia/monitoring': 1.54.0 + '@algolia/recommend': 5.54.0 + '@algolia/requester-browser-xhr': 5.54.0 + '@algolia/requester-fetch': 5.54.0 + '@algolia/requester-node-http': 5.54.0 + ansi-regex@6.2.2: {} ansi-styles@6.2.3: {} @@ -2175,6 +3426,8 @@ snapshots: atomic-sleep@1.0.0: {} + birpc@2.9.0: {} + c12@3.1.0: dependencies: chokidar: 4.0.3 @@ -2192,8 +3445,14 @@ snapshots: callsites@3.1.0: {} + ccount@2.0.1: {} + chai@6.2.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -2212,6 +3471,8 @@ snapshots: colorette@2.0.20: {} + comma-separated-tokens@2.0.3: {} + compare-func@2.0.0: dependencies: array-ify: 1.0.0 @@ -2236,6 +3497,10 @@ snapshots: convert-source-map@2.0.0: {} + copy-anything@4.0.5: + dependencies: + is-what: 5.5.0 + cosmiconfig-typescript-loader@6.3.0(@types/node@24.13.2)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3): dependencies: '@types/node': 24.13.2 @@ -2252,16 +3517,24 @@ snapshots: optionalDependencies: typescript: 5.9.3 + csstype@3.2.3: {} + dateformat@4.6.3: {} deepmerge-ts@7.1.5: {} defu@6.1.7: {} + dequal@2.0.3: {} + destr@2.0.5: {} detect-libc@2.1.2: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + discord-api-types@0.38.47: {} discord.js@14.26.3: @@ -2294,6 +3567,8 @@ snapshots: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 + emoji-regex-xs@1.0.0: {} + emoji-regex@10.6.0: {} empathic@2.0.0: {} @@ -2302,6 +3577,8 @@ snapshots: dependencies: once: 1.4.0 + entities@7.0.1: {} + env-paths@2.2.1: {} error-ex@1.3.4: @@ -2312,6 +3589,32 @@ snapshots: es-toolkit@1.46.1: {} + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -2343,6 +3646,8 @@ snapshots: escalade@3.2.0: {} + estree-walker@2.0.2: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 @@ -2367,6 +3672,10 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + focus-trap@7.8.0: + dependencies: + tabbable: 6.4.0 + fsevents@2.3.3: optional: true @@ -2395,8 +3704,30 @@ snapshots: dependencies: ini: 6.0.0 + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + help-me@5.0.0: {} + hookable@5.5.3: {} + + html-void-elements@3.0.0: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -2410,6 +3741,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-what@5.5.0: {} + jiti@2.6.1: {} joycon@3.1.1: {} @@ -2528,10 +3861,45 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + mark.js@8.11.1: {} + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + meow@13.2.0: {} + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-encode@2.0.1: {} + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + minimist@1.2.8: {} + minisearch@7.2.0: {} + + mitt@3.0.1: {} + nanoid@3.3.12: {} node-fetch-native@1.6.7: {} @@ -2552,6 +3920,12 @@ snapshots: dependencies: wrappy: 1.0.2 + oniguruma-to-es@3.1.1: + dependencies: + emoji-regex-xs: 1.0.0 + regex: 6.1.0 + regex-recursion: 6.0.2 + oxfmt@0.54.0: dependencies: tinypool: 2.1.0 @@ -2665,6 +4039,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + preact@10.29.2: {} + prisma@6.19.3(typescript@5.9.3): dependencies: '@prisma/config': 6.19.3 @@ -2676,6 +4052,8 @@ snapshots: process-warning@5.0.0: {} + property-information@7.2.0: {} + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -2696,12 +4074,24 @@ snapshots: real-require@1.0.0: {} + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + require-from-string@2.0.2: {} resolve-from@4.0.0: {} resolve-from@5.0.0: {} + rfdc@1.4.1: {} + rolldown@1.0.3: dependencies: '@oxc-project/types': 0.133.0 @@ -2723,12 +4113,56 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.3 '@rolldown/binding-win32-x64-msvc': 1.0.3 + rollup@4.61.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.61.1 + '@rollup/rollup-android-arm64': 4.61.1 + '@rollup/rollup-darwin-arm64': 4.61.1 + '@rollup/rollup-darwin-x64': 4.61.1 + '@rollup/rollup-freebsd-arm64': 4.61.1 + '@rollup/rollup-freebsd-x64': 4.61.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 + '@rollup/rollup-linux-arm-musleabihf': 4.61.1 + '@rollup/rollup-linux-arm64-gnu': 4.61.1 + '@rollup/rollup-linux-arm64-musl': 4.61.1 + '@rollup/rollup-linux-loong64-gnu': 4.61.1 + '@rollup/rollup-linux-loong64-musl': 4.61.1 + '@rollup/rollup-linux-ppc64-gnu': 4.61.1 + '@rollup/rollup-linux-ppc64-musl': 4.61.1 + '@rollup/rollup-linux-riscv64-gnu': 4.61.1 + '@rollup/rollup-linux-riscv64-musl': 4.61.1 + '@rollup/rollup-linux-s390x-gnu': 4.61.1 + '@rollup/rollup-linux-x64-gnu': 4.61.1 + '@rollup/rollup-linux-x64-musl': 4.61.1 + '@rollup/rollup-openbsd-x64': 4.61.1 + '@rollup/rollup-openharmony-arm64': 4.61.1 + '@rollup/rollup-win32-arm64-msvc': 4.61.1 + '@rollup/rollup-win32-ia32-msvc': 4.61.1 + '@rollup/rollup-win32-x64-gnu': 4.61.1 + '@rollup/rollup-win32-x64-msvc': 4.61.1 + fsevents: 2.3.3 + safe-stable-stringify@2.5.0: {} + search-insights@2.17.3: {} + secure-json-parse@4.1.0: {} semver@7.7.4: {} + shiki@2.5.0: + dependencies: + '@shikijs/core': 2.5.0 + '@shikijs/engine-javascript': 2.5.0 + '@shikijs/engine-oniguruma': 2.5.0 + '@shikijs/langs': 2.5.0 + '@shikijs/themes': 2.5.0 + '@shikijs/types': 2.5.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + siginfo@2.0.0: {} sonic-boom@4.2.1: @@ -2737,6 +4171,10 @@ snapshots: source-map-js@1.2.1: {} + space-separated-tokens@2.0.2: {} + + speakingurl@14.0.1: {} + split2@4.2.0: {} stackback@0.0.2: {} @@ -2749,12 +4187,23 @@ snapshots: get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 strip-json-comments@5.0.3: {} + superjson@2.2.6: + dependencies: + copy-anything: 4.0.5 + + tabbable@6.4.0: {} + thread-stream@4.2.0: dependencies: real-require: 1.0.0 @@ -2772,6 +4221,8 @@ snapshots: tinyrainbow@3.1.0: {} + trim-lines@3.0.1: {} + ts-mixer@6.0.4: {} tslib@2.8.1: {} @@ -2788,6 +4239,49 @@ snapshots: undici@6.24.1: {} + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@5.4.21(@types/node@24.13.2)(lightningcss@1.32.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.15 + rollup: 4.61.1 + optionalDependencies: + '@types/node': 24.13.2 + fsevents: 2.3.3 + lightningcss: 1.32.0 + vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.4)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 @@ -2803,6 +4297,55 @@ snapshots: tsx: 4.22.4 yaml: 2.9.0 + vitepress@1.6.4(@algolia/client-search@5.54.0)(@types/node@24.13.2)(lightningcss@1.32.0)(postcss@8.5.15)(search-insights@2.17.3)(typescript@5.9.3): + dependencies: + '@docsearch/css': 3.8.2 + '@docsearch/js': 3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3) + '@iconify-json/simple-icons': 1.2.86 + '@shikijs/core': 2.5.0 + '@shikijs/transformers': 2.5.0 + '@shikijs/types': 2.5.0 + '@types/markdown-it': 14.1.2 + '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@24.13.2)(lightningcss@1.32.0))(vue@3.5.38(typescript@5.9.3)) + '@vue/devtools-api': 7.7.9 + '@vue/shared': 3.5.38 + '@vueuse/core': 12.8.2(typescript@5.9.3) + '@vueuse/integrations': 12.8.2(focus-trap@7.8.0)(typescript@5.9.3) + focus-trap: 7.8.0 + mark.js: 8.11.1 + minisearch: 7.2.0 + shiki: 2.5.0 + vite: 5.4.21(@types/node@24.13.2)(lightningcss@1.32.0) + vue: 3.5.38(typescript@5.9.3) + optionalDependencies: + postcss: 8.5.15 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/node' + - '@types/react' + - async-validator + - axios + - change-case + - drauu + - fuse.js + - idb-keyval + - jwt-decode + - less + - lightningcss + - nprogress + - qrcode + - react + - react-dom + - sass + - sass-embedded + - search-insights + - sortablejs + - stylus + - sugarss + - terser + - typescript + - universal-cookie + vitest@4.1.8(@types/node@24.13.2)(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.4)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.8 @@ -2830,6 +4373,16 @@ snapshots: transitivePeerDependencies: - msw + vue@3.5.38(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-sfc': 3.5.38 + '@vue/runtime-dom': 3.5.38 + '@vue/server-renderer': 3.5.38(vue@3.5.38(typescript@5.9.3)) + '@vue/shared': 3.5.38 + optionalDependencies: + typescript: 5.9.3 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -2860,3 +4413,5 @@ snapshots: string-width: 7.2.0 y18n: 5.0.8 yargs-parser: 22.0.0 + + zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f9a0079..4e50d0a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,11 @@ +packages: + - "." + - "docs" + allowBuilds: '@prisma/client': true '@prisma/engines': true - esbuild: false + esbuild: true lefthook: false prisma: true From bd9682c72685b75e50de961cba2e5b96688c0741 Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:26:11 +0200 Subject: [PATCH 02/14] docs: remove old markdown files replaced by VitePress - Remove modules.md, commands.md, listeners.md, interactions.md, services.md, prisma.md, functional.md (moved to _internal/) - Remove specs/ and review/ directories (moved to _internal/) --- docs/functional.md | 66 ------ docs/review/config-completion-findings.md | 138 ------------ docs/review/dev-guild-commands-findings.md | 79 ------- docs/specs/autopin.md | 76 ------- docs/specs/module-config.md | 248 --------------------- docs/specs/thread-creator-queue.md | 47 ---- 6 files changed, 654 deletions(-) delete mode 100644 docs/functional.md delete mode 100644 docs/review/config-completion-findings.md delete mode 100644 docs/review/dev-guild-commands-findings.md delete mode 100644 docs/specs/autopin.md delete mode 100644 docs/specs/module-config.md delete mode 100644 docs/specs/thread-creator-queue.md diff --git a/docs/functional.md b/docs/functional.md deleted file mode 100644 index 78c3e01..0000000 --- a/docs/functional.md +++ /dev/null @@ -1,66 +0,0 @@ -# Fonctionnement du bot - -Documentation du comportement visible par les utilisateurs et administrateurs de serveur Discord. - ---- - -## Module Core - -Toujours actif, non désinstallable. Fournit la gestion des modules pour les administrateurs. - -### `/modules` — Gérer les modules du serveur - -**Permission requise :** Administrateur - -Affiche la liste de tous les modules disponibles avec leur statut sur le serveur (activé/désactivé), leur version activée, et leur description. Chaque module dispose d'un bouton **Activer** (vert) ou **Désactiver** (rouge) qui prend effet immédiatement. - ---- - -## Module Thread Creator - -Crée automatiquement un fil de discussion sous chaque nouveau message dans un salon configuré. Remplace le bot Needle. - -### Comportement automatique - -Dès qu'un message est posté dans le salon configuré : - -1. Le bot crée un fil dont le nom est généré depuis le template configuré -2. Si un message de bienvenue est configuré, le bot le poste dans le fil - -**Variables disponibles dans le template de nom :** -| Variable | Valeur | -|---|---| -| `{messageAuthor}` | Nom d'affichage ou pseudo de l'auteur | -| `{messageContent}` | 50 premiers caractères du message | -| `{timestamp}` | Heure au format `JJ/MM HH:MM` (locale française) | - -**Template par défaut :** `Discussion - {messageAuthor}` -**Message de bienvenue par défaut :** `💬 Utilisez ce fil pour discuter de ce sujet !` - -**Limites :** - -- Noms de fils tronqués à 100 caractères (limite Discord) -- Rate limit : 5 fils max par fenêtre de 10 secondes par serveur — les créations excédentaires sont **mises en file d'attente** (FIFO, par serveur) et traitées dès que la fenêtre se libère, au lieu d'être ignorées. File en mémoire : perdue au redémarrage. -- Messages de bots ignorés -- Ne fonctionne pas dans les fils, salons vocaux, forum ou annonces - -**Erreurs gérées silencieusement :** - -- Message supprimé avant création du fil -- Limite de fils atteinte sur le salon -- Permissions insuffisantes - -### Configuration — `/config thread-creator` - -Depuis la v2.0.0, le module utilise le système de configuration générique. Il n'a -plus de commande dédiée : la configuration se fait via `/config thread-creator` -(réservé aux administrateurs) et l'activation/désactivation via `/modules`. - -| Champ | Type | Description | -| -------------------- | -------------- | -------------------------------------------------------------------------------------------- | -| `channels` | Salons (liste) | Salons à surveiller (un ou plusieurs, multi-select). Liste vide = rien n'est surveillé. | -| `welcomeMessage` | Texte | Message posté automatiquement dans chaque fil créé. | -| `threadNameTemplate` | Texte | Template du nom des fils — variables : `{messageAuthor}`, `{messageContent}`, `{timestamp}`. | - -Il n'y a plus de flag `actif` : désactiver le module via `/modules` arrête la -surveillance sans effacer la configuration. diff --git a/docs/review/config-completion-findings.md b/docs/review/config-completion-findings.md deleted file mode 100644 index 5f9f45a..0000000 --- a/docs/review/config-completion-findings.md +++ /dev/null @@ -1,138 +0,0 @@ -# Revue de code — complétion du système de configuration - -Findings de la revue du commit `feat(config): complete editing for number and -entity field types` (+ module `test-config`). À traiter ultérieurement. - -Légende statut : [ ] à faire · [x] fait - ---- - -## Bugs (à corriger) - -### [x] #1 — `config.get` ment sur la nullabilité des valeurs non définies - -- **Fichier :** `src/lib/config.ts` (`ConfigData` / `ConfigProvider.get`), - `src/core/services/config.service.ts` (`createDefaultConfigForModule`) -- **Problème :** un champ sans `defaultValue` n'a pas de valeur, mais `config.get` - le type comme toujours présent (`ResolveType`). Pour les entités - (`USER`/`ROLE`/`CHANNEL`/`CATEGORY`) la valeur réelle est absente ; pour - `STRING`/`NUMBER`/`BOOLEAN` le service fabrique de faux défauts (`""`/`0`/`false`) - qui masquent l'état « non défini ». -- **Scénario d'échec :** un module fait `config.get("user").username` → compile - sans erreur → `TypeError` au runtime quand le champ n'a jamais été configuré. -- **Sémantique cible :** - - `undefined` = jamais défini ; - - `null` = vidé intentionnellement (action « clear » future) ; - - un champ **avec** `defaultValue` est toujours présent → **pas** de `| undefined`. -- **Fix proposé :** - - Typage conditionnel sur la présence de `defaultValue` : - ```ts - type ConfigEntryValue> = E extends { - defaultValue: unknown; - } - ? ResolveType - : ResolveType | undefined; - ``` - utilisé par `ConfigData` et `ConfigProvider.get`. - - Runtime : `createDefaultConfigForModule` ne pose une valeur que si - `defaultValue` est déclaré (sinon clé absente → `undefined`), au lieu de - fabriquer `""`/`0`/`false`/`null`. - - Garder `(config.get(key) ?? "").toString()` dans les `replyToEditRequest` - des handlers string/number (la valeur peut désormais être `undefined`). - -### [x] #2 — Un champ de type liste affiche un bouton « éditer » mort - -- **Fichiers :** `src/core/utils/core.messages.ts`, - `src/core/interactions/configure-module.button.ts` -- **Problème :** `configurationMessage` posait un bouton `configure-module` pour - tout type `!= BOOLEAN`, donc aussi pour un type tableau (`ListOf`). Au clic, - `configure-module.button` faisait `if (Array.isArray(schemaDef.type)) return;` - → no-op silencieux. -- **Fait :** l'édition des listes est désormais implémentée — `configure-module` - route les listes d'entités vers le multi-select et les listes scalaires vers - l'éditeur ajouter/supprimer (`scalar-list-editor.ts`). Plus de bouton mort. - ---- - -## Inefficacité (optionnel) - -### [ ] #3 — Double désérialisation dans le toggle booléen - -- **Fichier :** `src/core/interactions/toggle-option.button.ts` (l.22 puis l.36) -- **Problème :** `getConfigForModuleIn` puis `updateConfigForModuleIn` - désérialisent chacun les entités (`deserializeConfigData` → fetch guild + - entités Discord), alors qu'on ne change qu'un booléen. -- **Fix proposé :** lire la valeur booléenne courante via un chemin léger (cache - sérialisé) sans désérialiser, et laisser `updateConfigForModuleIn` faire la - seule passe nécessaire pour le rendu. -- **Note :** la racine (`deserializeConfigData` qui `fetch` la guild même sans - champ entité) est pré-existante dans `config.service.ts`, hors périmètre strict - du diff mais à garder en tête. - ---- - -## Nettoyage (optionnel) - -### [ ] #4 — Boilerplate des 4 handlers d'entité - -- **Fichiers :** `src/core/config/{user,role,channel,category}-config-handler.ts` -- **Problème :** 4 sous-classes quasi identiques (~42 lignes chacune) ne variant - que par builder de select, placeholder, filtre de type de salon et type guard. -- **Fix proposé :** rendre la base `EntitySelectConfigHandler` pilotée par une - table de données `{ selectCustomId, buildMenu, channelTypes?, guard }` plutôt - que par héritage — supprime ~150 lignes. - -### [ ] #5 — Construction de modal dupliquée string/number - -- **Fichiers :** `src/core/config/string-config-handler.ts`, - `number-config-handler.ts` -- **Problème :** le modal (ModalBuilder → ActionRow → TextInput) et le flux de - soumission sont quasi identiques ; seuls `customId`, label et validation - diffèrent. -- **Fix proposé :** helper partagé `buildTextInputModal(...)` dans - `config-edit.helpers.ts`. - ---- - -## Améliorations UX (feature config) - -### [x] #6 — Éditer/remplacer le message de config existant après soumission de modale - -- **Fichiers :** `src/core/config/string-config-handler.ts`, - `number-config-handler.ts` (soumission de modale) -- **Problème :** après soumission d'une modale, on faisait `interaction.reply(...)` - → un **nouvel** embed de configuration en doublon du message `/config`. -- **Fait :** la soumission de modale fait `interaction.update(...)` (via le garde - `isFromMessage()`) → le message de config est édité **en place**, plus de - doublon. Les toggles et select menus éditent déjà en place. - -### [x] #7 — Rendre la configuration visible de tous (non-ephemeral) - -- **Fichiers :** `src/core/commands/config.command.ts`, - `configure-module.button.ts`, `toggle-option.button.ts` -- **Problème :** modifier des paramètres qui impactent tout le serveur ne devrait - pas être caché ; mais rendre le message public expose ses boutons d'édition à - tous, or les handlers d'édition ne vérifiaient pas les permissions - (contrairement à enable/disable) → **escalade** (n'importe qui pourrait éditer). -- **Fait :** `/config` est désormais **public**. La vérification de permission - est **centralisée** : un flag déclaratif `requiresAdmin` sur - `InteractionHandler`, enforcé une seule fois par le dispatcher - (`interaction-create.listener`) avant d'exécuter le handler. Tous les handlers - d'édition config + les boutons enable/disable portent `requiresAdmin: true` ; - plus aucun appel `requireAdmin` inline (future-proof : un nouveau handler - sensible n'a qu'à poser le flag). `requireAdmin` accepte toute - `CompatibleInteraction`. Les éditeurs entité/liste restent ephemeral ; les - toggles/modales éditent le message public en place. -- **Refresh du message public :** les éditeurs entité/liste restent ephemeral - mais rafraîchissent le message public d'origine après chaque modification - (`refreshSourceConfigMessage` : id du message public threadé dans les `customId`, - puis `channel.messages.fetch(id).edit(...)`). Invariant associé : aucune vue - config n'est rendue sur un message ephemeral (le submit d'un select re-rend le - select), sinon ses boutons « Éditer » pointeraient vers un message non éditable. -- **Affichage :** les entités s'affichent en mentions rendues (`@rôle`, `#salon`) - via `renderCurrentValue` (hors backticks ; scalaires entre backticks). - ---- - -> Tâches transverses au projet (commandes guild en dev, ergonomie des imports) -> déplacées dans `AUDIT.md`. diff --git a/docs/review/dev-guild-commands-findings.md b/docs/review/dev-guild-commands-findings.md deleted file mode 100644 index 1c89945..0000000 --- a/docs/review/dev-guild-commands-findings.md +++ /dev/null @@ -1,79 +0,0 @@ -# Revue de code — enregistrement des commandes en mode dev (dev guild) - -Findings de la revue du travail dev-guild (audit #23 + #25, encore non commité au -moment de la revue) : `loadDevGuildCommands`, branchement dev/prod dans -`index.ts`, `env.ts`, `validate-env-vars.mjs`, script `dev`, test d'intégration. - -Le diff est globalement sain — aucun bug bloquant. Rangé du plus actionnable au -moins prioritaire. - -Légende statut : [ ] à faire · [x] fait - ---- - -## À corriger - -### [x] #1 — `loadDevGuildCommands` ne fait pas `await` sur le `rest.put` - -- **Fichier :** `src/core/loaders/command-loader.ts` (`loadDevGuildCommands`, et - même pattern dans `loadGlobalCommands`) -- **Problème :** la fonction est `async` et est `await`ée par `index.ts`, mais elle - chaîne `rest.put(...).then().catch()` sans `await`/`return`. Elle résout donc - avant la fin du PUT ; l'erreur n'est captée que dans le `.catch` (pas propagée), - et le « ready » est loggé avant l'enregistrement effectif. Incohérent avec - `installModuleCommandsIn` qui fait `await`. -- **Scénario :** un PUT qui échoue (token invalide, rate limit, body > 100 - commandes) n'est que loggé ; le démarrage continue comme si tout allait bien. -- **Fait :** `await rest.put(...)` dans un `try/catch` sur `loadDevGuildCommands` - **et** `loadGlobalCommands` (rendue `async`, désormais `await`ée dans - `index.ts`). - -### [x] #2 — Le test d'intégration n'assert pas la présence des commandes core - -- **Fichier :** `src/core/loaders/command-loader.integration.test.ts` -- **Problème :** `putBodyNames()` ne vérifiait que les commandes de module ; aucun - test n'assertait que les commandes du core sont incluses dans le body du PUT dev. -- **Scénario :** une régression retirant `coreModule.registry.commands` de - l'agrégat passerait les tests au vert → fausse couverture. -- **Fait :** `core.module.js` mocké avec une commande core connue ; assertions - ajoutées (présence de `core-cmd` dans le PUT, et un test « core seul, sans - module » → body == `["core-cmd"]`). - ---- - -## Optionnel - -### [ ] #3 — Requêtes d'état des modules séquentielles - -- **Fichier :** `src/core/loaders/command-loader.ts` (`loadDevGuildCommands`) -- **Problème :** `getModuleStateFromGuildIdIn` est `await`é par module dans la - boucle → N requêtes DB en série au démarrage. -- **Fix :** paralléliser via `Promise.all` sur les états, puis filtrer. Impact - faible aujourd'hui (peu de modules), réel à l'échelle. - -### [ ] #4 — Duplication REST + logging entre `loadGlobalCommands` et `loadDevGuildCommands` - -- **Fichier :** `src/core/loaders/command-loader.ts` -- **Problème :** construction du client REST + bloc `.then/.catch` de logging par - commande dupliqués. -- **Fix :** extraire `registerCommands(rest, route, body, label)` pour éviter la - divergence dev/prod. (Recouvre aussi la répétition de - `registry.commands.map(c => c.data.toJSON())`, présente à 3-4 endroits.) - -### [x] #5 — `index.ts` connaît les deux flux d'enregistrement (altitude) - -- **Fichier :** `src/index.ts` (handler `ClientReady`) -- **Problème :** le caller encode en détail dev (agrégat) vs prod (version-gate + - global). Toute évolution future doit choisir « dev / prod / les deux » et - toucher `index.ts`. -- **Fait :** point d'entrée unique `syncCommands(client, modules)` dans - `command-loader.ts` qui possède l'aiguillage dev/prod ; `index.ts` l'appelle en - une ligne (6888918). - -### [ ] #6 — Littéral `"development"` dupliqué - -- **Fichiers :** `bootstrap/validate-env-vars.mjs` et `src/lib/env.ts` - (`isDevMode`) -- **Problème :** la définition du mode dev (`NODE_ENV === "development"`) existe à - deux endroits ; le `.mjs` bootstrap ne peut pas importer le `.ts` facilement. -- **Fix :** extraire une petite constante partagée importable des deux côtés. diff --git a/docs/specs/autopin.md b/docs/specs/autopin.md deleted file mode 100644 index 73ab59d..0000000 --- a/docs/specs/autopin.md +++ /dev/null @@ -1,76 +0,0 @@ -# Spec — Module Autopin - -Issues : [#15](https://github.com/AsyncCommunityDiscord/OmniBot/issues/15), [#16](https://github.com/AsyncCommunityDiscord/OmniBot/issues/16) -Priorité : moyenne - ---- - -## Objectif - -Remplacer le bot externe Pinpal. Maintenir un message "ancré" en bas d'un salon en le supprimant et le repostant à chaque nouvelle activité dans le salon. - -## Comportement - -À chaque nouveau message dans un salon configuré, le bot : - -1. Supprime le message ancré précédent (posté par le bot) -2. Reposte le contenu ancré en bas du salon -3. Mémorise l'ID du nouveau message pour la prochaine occurrence - -Le message ancré est toujours le dernier message visible dans le salon. - -## Commandes - -### `/autopin set` - -**Permission requise :** Gérer les salons - -| Paramètre | Type | Obligatoire | Description | -| ------------ | ------------- | ----------- | ----------------------------------- | -| `salon` | Salon textuel | Oui | Salon dans lequel ancrer le message | -| `message-id` | Texte | Oui | ID du message Discord à ancrer | - -Configure l'ancrage et poste immédiatement le message en bas du salon. - -### `/autopin disable` - -**Permission requise :** Gérer les salons - -Désactive l'ancrage sur le salon. Le dernier message ancré posté par le bot est supprimé ou laissé en place (à définir). - -### `/autopin status` - -**Permission requise :** Gérer les salons - -Affiche le salon configuré et un aperçu du contenu ancré. Réponse éphémère. - -## Permissions requises pour le bot - -- Lire les messages du salon -- Envoyer des messages dans le salon -- Supprimer les messages (au minimum les siens) - -## Schéma de données - -```prisma -model AutopinConfig { - guildId String @id - channelId String - pinnedContent String @db.Text - lastMessageId String? - enabled Boolean @default(true) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} -``` - -## Cas limites à gérer - -- Le bot n'a pas la permission de supprimer son propre message → warning loggé, nouvelle tentative ignorée -- Le message source (celui fourni à `/autopin set`) est supprimé → le contenu ancré doit rester opérationnel (il est stocké en base, pas recalculé) -- Salon très actif → le bot peut générer du spam de suppression/repost ; une option de fréquence minimum (ex. toutes les 5 minutes) est envisagée comme amélioration ultérieure - -## Ce qui est hors scope (v1) - -- Plusieurs messages ancrés par salon -- Fréquence de réancrage configurable diff --git a/docs/specs/module-config.md b/docs/specs/module-config.md deleted file mode 100644 index d332920..0000000 --- a/docs/specs/module-config.md +++ /dev/null @@ -1,248 +0,0 @@ -# Spec — Système de configuration des modules - -Issue : [#14](https://github.com/AsyncCommunityDiscord/OmniBot/issues/14) -Priorité : haute — assignée à RedsTom, jalon « Finish the module library ». - -> Cette spec décrit l'architecture **réellement implémentée** (branche `feat/config`) -> et formalise le travail restant pour clore la fonctionnalité. Elle remplace la -> proposition normalisée initiale (`/config view|set|reset` + table `ModuleConfig`), -> abandonnée au profit d'une UI interactive et d'un stockage en blob JSON. - ---- - -## Objectif - -Permettre à chaque module de déclarer un schéma de configuration **typé**, -persistant en base par serveur, consultable et modifiable par les administrateurs -via une interface Discord interactive. - -## Types de champs supportés - -| Type | Saisie | Stockage (JSON) | Lecture (désérialisé) | -| ---------- | ------------------------ | ---------------- | --------------------- | -| `STRING` | Modal (texte) | `string` | `string` | -| `NUMBER` | Modal (texte → nombre) | `number` | `number` | -| `BOOLEAN` | Bouton toggle | `boolean` | `boolean` | -| `USER` | Select menu utilisateur | `string` (id) | `User` | -| `ROLE` | Select menu rôle | `string` (id) | `Role` | -| `CHANNEL` | Select menu salon | `string` (id) | `Channel` | -| `CATEGORY` | Select menu catégorie | `string` (id) | `CategoryChannel` | -| `ENUM` | Select menu (choix fixe) | `string` (choix) | union littérale¹ | - -¹ `ENUM` représente un choix parmi un ensemble fixe déclaré sur l'entrée via -`options`. La valeur stockée et lue est l'une de ces options (un `string`). Si -`options` est déclaré `as const`, `config.get(...)` est typé comme l'**union -littérale** des valeurs (`"light" | "dark"`), sinon `string`. Voir -[Type `ENUM`](#type-enum-choix-fixe). - -### Listes (`ListOf`) - -N'importe quel type peut être déclaré en **liste** via `type: [ConfigType.X]`. La -valeur lue est alors un tableau (`X[]`). L'édition dépend du type de base : - -- **Entités** (`USER`/`ROLE`/`CHANNEL`/`CATEGORY`) → **multi-select** natif - (jusqu'à 25 éléments, pré-sélection des valeurs courantes). -- **`ENUM`** (`[ConfigType.ENUM]`) → **multi-select** sur les `options` déclarées - (min 0 pour autoriser le vidage, max = nombre d'options) ; pré-sélection des - valeurs courantes. -- **Scalaires** (`STRING`/`NUMBER`) → **éditeur dédié** : un message listant - chaque élément avec un bouton _Supprimer_, plus un bouton _Ajouter_ qui ouvre - une modale validée par le type. -- **Booléens en liste** (`[BOOLEAN]`) → même éditeur, mais chaque élément est un - **toggle** (bascule vrai/faux en place) ; _Ajouter_ insère directement un - `false` (pas de modale). - -## API pour les modules - -Un module déclare son schéma dans `defineModule({ ..., config: { ... } })` : - -```ts -config: { - logChannel: { - name: "Salon de logs", - description: "Salon où poster les logs", - type: ConfigType.CHANNEL, - }, - maxWarnings: { - name: "Avertissements max", - description: "Nombre d'avertissements avant sanction", - type: ConfigType.NUMBER, - defaultValue: 3, - }, -} -``` - -Lecture des valeurs (désérialisées) côté composants du module : - -```ts -async execute(interaction, config) { - const channel = config.get("logChannel"); // Channel | undefined (pas de défaut) - const max = config.get("maxWarnings"); // number (a un defaultValue) -} -``` - -Typage des valeurs : un champ **avec** `defaultValue` est toujours présent ; un -champ **sans** défaut peut être `undefined` (jamais défini). `null` est réservé à -une valeur effacée intentionnellement. Voir `ConfigEntryValue` dans -`src/lib/config.ts`. - -### Type `ENUM` (choix fixe) - -Un champ `ENUM` déclare un ensemble fixe de valeurs autorisées via `options` : - -```ts -config: { - logLevel: { - name: "Niveau de log", - description: "Verbosité des logs", - type: ConfigType.ENUM, - options: ["debug", "info", "warn", "error"] as const, // `as const` → union littérale - defaultValue: "info", - }, - // Liste : plusieurs choix parmi le même ensemble (multi-select) - enabledFeatures: { - name: "Fonctionnalités", - description: "Modules optionnels activés", - type: [ConfigType.ENUM], - options: ["welcome", "logs", "automod"] as const, - }, -} -``` - -- `options` est **obligatoire** sur une entrée `ENUM` (le type l'exige). -- `as const` fait que `config.get("logLevel")` est typé `"debug" | "info" | -"warn" | "error"` (l'union littérale) ; sans `as const`, c'est `string`. -- La valeur est stockée telle quelle (un `string`) ; aucune désérialisation. - -Le `ConfigProvider` est injecté automatiquement dans `execute`/`complete`/`check` -des commandes, listeners et interaction handlers (voir -`interaction-create.listener.ts`, `listener-loader.ts`). - -## Persistance - -Stockage en **un blob JSON par serveur** (et non une table normalisée) : - -```prisma -model GuildConfiguration { - guildId String @id - data Json -} -``` - -- `data` mappe `moduleId -> { clé: valeur sérialisée }`. -- Les entités Discord (user/role/channel/category) sont stockées par **id** et - réhydratées à la lecture par `ConfigService.deserializeConfigData`. -- Un cache en mémoire (`configCache`) évite un aller-retour base à chaque lecture ; - il est invalidé à chaque écriture. -- Les valeurs par défaut sont matérialisées à la création de la config du serveur. - -## Interface admin - -### Commande `/config ` - -- Option `module` requise, avec autocomplétion (modules activés + core). -- Réservée aux administrateurs (`setDefaultMemberPermissions`). -- Réponse **publique** (Components V2) : une modification impactant tout le - serveur ne doit pas être cachée. Comme le message est public, les - interactions d'édition sont réservées aux admins via le flag déclaratif - `requiresAdmin` (sur `InteractionHandler`), enforcé centralement par le - dispatcher d'interactions. -- Liste chaque option : nom, description, type, valeur courante, et un accessoire - d'édition selon le type : - - bouton **toggle** pour les booléens (`toggle-option`) ; - - bouton **éditer** pour tous les autres types (`configure-module`). -- **Pagination** : chaque champ coûte 3 composants (section + texte + bouton) et - Discord plafonne un message à **40 composants**. Le panneau affiche donc - `CONFIG_FIELDS_PER_PAGE` champs par page (10) avec une barre _◀ Précédent / - Suivant ▶_ (`config-page::`) qui ré-affiche le panneau en place. - La barre n'apparaît qu'au-delà d'une page. Après une édition, le panneau se - ré-affiche sur la **page contenant le champ modifié** : cette page est - **déduite** de la position de la clé dans le schéma (`configPageOfKey`), donc - aucun `page` n'est threadé dans les `customId` (contrairement à - `sourceMessageId`). Comme un admin ne peut cliquer que sur la page affichée, la - page déduite est toujours celle qu'il regardait. -- **Limitation multi-admin** (assumée) : le panneau étant **un seul message - public partagé**, sa page courante est un état **global**, pas par-utilisateur. - Deux admins ne peuvent pas naviguer indépendamment, et l'action de l'un - re-rend le message pour tous. C'est purement cosmétique (la persistance est - toujours correcte) et rare ; le seul vrai correctif serait un panneau ephemeral - par-utilisateur, écarté par choix (panneau public, voir #7). - -### Flux d'édition - -Le bouton `configure-module::` ouvre l'éditeur adapté au type -(`configure-module.button.ts` route selon scalaire/entité et selon liste) : - -- `STRING`/`NUMBER` (scalaire) : **modal** texte ; -- `USER`/`ROLE`/`CHANNEL`/`CATEGORY` (scalaire ou liste) : **select menu** natif - (mono ou multi selon liste), ephemeral, V2 ; -- `ENUM` (scalaire ou liste) : **string select menu** rempli avec les `options` - de l'entrée (mono ou multi selon liste), ephemeral, V2 (`enum.config-handler.ts`) ; -- listes scalaires (`STRING`/`NUMBER`/`BOOLEAN`) : **éditeur ajouter/supprimer** - (`scalar-list-editor.ts`). - -La soumission (modal submit, select, ou ajout/suppression) **valide**, **persiste** -via `ConfigService.updateConfigForModuleIn`, puis **réaffiche** le message public. - -- Les éditions directes (modale `STRING`/`NUMBER`, toggle booléen) éditent le - message de config **public en place** (`interaction.update`), sans nouvel embed. -- Les select menus d'entité et l'éditeur de listes scalaires sont des messages - **ephemeral** séparés (visibles du seul admin). Après chaque modification ils - rafraîchissent le message public d'origine via - `refreshSourceConfigMessage` : l'id du message public est threadé dans les - `customId` des composants de l'éditeur, et le service ré-édite ce message - (`channel.messages.fetch(id).edit(...)`). -- **Invariant** : aucune vue config (`configurationMessage`) n'est jamais rendue - sur un message ephemeral — sinon ses boutons « Éditer » pointeraient vers un - message ephemeral non éditable par id. Le submit d'un select d'entité re-rend - donc **le select** (avec la sélection à jour), pas une vue config. - -### Affichage des valeurs - -`renderCurrentValue` (dans `core.messages.ts`) rend les **entités** sous forme de -mentions **hors backticks** (Discord les affiche en `@rôle` / `#salon`) et les -**scalaires** entre backticks. Les listes sont jointes ; une valeur absente -s'affiche `—`. - -## Validation - -`ConfigValidator` (dans `src/lib/config.ts`) fournit un prédicat par type, exposé -via `ConfigTypeHandler.validate(value)` : - -- `NUMBER` : chaîne convertible en nombre fini ; -- `BOOLEAN` : `"true"` / `"false"` ; -- `USER`/`ROLE`/`CHANNEL`/`CATEGORY` : mention **ou** identifiant brut (snowflake) — - les select menus renvoyant des ids bruts ; -- `STRING` : toujours valide ; -- `ENUM` : le prédicat générique accepte tout (il n'a pas accès aux `options`) ; - l'appartenance à `options` est vérifiée par `EnumConfigHandler`, qui rejette - toute valeur soumise hors de l'ensemble déclaré. - -Pour les listes, chaque élément est validé individuellement (par valeur du -select pour les entités et les enums, à l'ajout dans l'éditeur pour les scalaires). - -## Travail réalisé - -- [x] Soumission du modal `NUMBER` (parsing + validation + sauvegarde). -- [x] Handlers `USER`/`ROLE`/`CHANNEL`/`CATEGORY` (select menus). -- [x] Ids bruts acceptés dans les validateurs d'entités. -- [x] Suppression du code mort `editionSection` / `editedField`. -- [x] Tests (lib + handlers : modal, select, éditeur de liste). -- [x] Édition des listes : multi-select pour les entités, éditeur - ajouter/supprimer pour les scalaires. -- [x] Type `ENUM` (choix fixe parmi `options`), scalaire et liste, édité via - string select menu, avec typage en union littérale. -- [x] Pagination du panneau `/config` (10 champs/page) pour respecter le plafond - de 40 composants de Discord. - -## Hors périmètre / suites possibles - -- Notification des modules sur changement de configuration (hook `onConfigChange`). - -## Migrations réalisées - -- **Thread Creator** (v2.0.0) : migré de sa table dédiée `ThreadCreatorConfig` - vers ce système générique (clean cut, sans reprise de données). La commande - `/thread-config` et le flag `enabled` ont été supprimés — la configuration se - fait via `/config thread-creator` et l'activation via `/modules`. La table - `thread_creator_configs` a été supprimée (migration `drop_thread_creator_config`). diff --git a/docs/specs/thread-creator-queue.md b/docs/specs/thread-creator-queue.md deleted file mode 100644 index 1abfdb8..0000000 --- a/docs/specs/thread-creator-queue.md +++ /dev/null @@ -1,47 +0,0 @@ -# Spec — Thread Creator : file d'attente de création - -Issues : [#36](https://github.com/AsyncCommunityDiscord/OmniBot/issues/36), [#37](https://github.com/AsyncCommunityDiscord/OmniBot/issues/37) -Priorité : basse - ---- - -> **Statut : implémenté.** File d'attente et multi-salons (#37) livrés : la classe `ThreadCreationQueue` (`services/thread-creation-queue.ts`) et le champ de config `channels` en `ListOf`. Voir « Implémentation » plus bas. - -## Problème (avant) - -Quand plusieurs messages arrivaient rapidement dans le salon surveillé, le rate limit de 5 fils par 10 secondes était atteint et les messages suivants étaient silencieusement ignorés. Des fils n'étaient donc jamais créés pour ces messages. - -## Comportement - -Le drop silencieux est remplacé par une **file d'attente par serveur** : si le rate limit est atteint, les créations de fils sont mises en attente et traitées dès que la fenêtre de 10 secondes se libère. - -### Règles - -- La file est propre à chaque serveur (pas de partage inter-serveurs). -- L'ordre de création respecte l'ordre d'arrivée des messages. -- Si le bot redémarre, les entrées en attente sont perdues (pas de persistance requise). -- Pas de limite de taille de file définie pour l'instant (à affiner selon les retours). - -### Pourquoi pas de persistance (décision assumée) - -La file est volontairement **en mémoire seule**. Ce qu'on perd à un redémarrage = uniquement les jobs en attente d'un **burst en cours** (le surplus au-delà de 5/10 s pas encore traité) : - -- **Sévérité faible** : les messages ne sont pas perdus (ils restent sur Discord) — on rate seulement le _fil auto_ sous certains messages d'un pic, ce qui est cosmétique et rattrapable. C'est l'ancien mode d'échec (drop sur rate limit), désormais réduit à « drop seulement si redémarrage pendant un backlog actif ». -- **Coût disproportionné** : un job référence un `Message` vivant (non sérialisable) → il faudrait persister `(messageId, channelId, …)`, **re-fetch** les messages au boot et gérer ceux supprimés entre-temps, plus une **table dédiée** — qu'on vient justement de supprimer (clean cut de la migration). Trop pour une feature `priority: low`. -- **Juste-milieu écarté** : un drain best-effort au graceful shutdown ne couvrirait que les deploys planifiés (pas les crashes) et resterait limité par le délai de grâce + le rate limit → bénéfice marginal. - -À reconsidérer seulement si la création de fil devient critique (modération/traçabilité) ou si des pics + redémarrages fréquents rendent la perte visible. - -## #37 — multi-salons - -L'issue #37 (configurer plusieurs salons par serveur) dépendait de cette file : sans elle, surveiller plusieurs salons amplifierait les drops. La file en place, le multi-salons est livré en passant le champ de config `channel` (salon unique) à **`channels: ListOf`** : le service crée un fil si le message est posté dans **l'un** des salons surveillés, et toutes les créations passent par la file (donc partagent la même fenêtre de rate limit par serveur). - -## Impact sur le schéma - -Aucun changement de schéma de base nécessaire (file en mémoire). Depuis la v2.0.0, le module n'a plus de table dédiée : sa configuration vit dans le système générique (`GuildConfiguration`, blob JSON par serveur). Le multi-salons s'est donc fait au niveau du schéma de config du module (`channel` → `channels: ListOf`), sans migration de table. **Clean cut** : les configs `channel` (singulier) déjà enregistrées ne sont pas reprises — les serveurs concernés re-sélectionnent leurs salons via `/config thread-creator`. - -## Implémentation - -- `services/thread-creation-queue.ts` — `ThreadCreationQueue` : file FIFO par serveur, cadence ≤ 5 / 10 s, reprise par `setTimeout` quand la fenêtre est pleine, drain non réentrant (un seul `pump` par serveur). Erreur sur un job loggée sans bloquer la file. -- `services/thread-creator.service.ts` — `scheduleThreadForMessage` : teste l'appartenance du salon à `channels`, génère le nom du fil, puis enfile le job. -- Tests : `services/thread-creation-queue.test.ts` (FIFO sans drop sur plusieurs fenêtres, cadence ≤ 5/10 s, isolation par serveur, message de bienvenue) avec fake timers. From da11c6dd2f7bb2a3fdc8dfe4a53d7eb3b19aad4d Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:26:31 +0200 Subject: [PATCH 03/14] docs(fr): add French documentation pages - Add landing page with feature overview - Add getting-started guide (architecture, conventions, imports) - Add creating-a-module guide (structure, lifecycle hooks) - Add commands guide (slash commands, registration, propagation) - Add listeners guide (event listeners, activation) - Add interactions guide (buttons, modals, select menus) - Add configuration guide (ConfigType, ENUM, lists, defaults) - Add services guide (business logic encapsulation) - Add database guide (Prisma multi-file schema, migrations) --- docs/fr/guide/commands.md | 64 +++++++++ docs/fr/guide/configuration.md | 153 +++++++++++++++++++++ docs/fr/guide/creating-a-module.md | 148 +++++++++++++++++++++ docs/fr/guide/database.md | 118 +++++++++++++++++ docs/fr/guide/getting-started.md | 73 ++++++++++ docs/fr/guide/interactions.md | 205 +++++++++++++++++++++++++++++ docs/fr/guide/listeners.md | 44 +++++++ docs/fr/guide/services.md | 53 ++++++++ docs/fr/index.md | 29 ++++ 9 files changed, 887 insertions(+) create mode 100644 docs/fr/guide/commands.md create mode 100644 docs/fr/guide/configuration.md create mode 100644 docs/fr/guide/creating-a-module.md create mode 100644 docs/fr/guide/database.md create mode 100644 docs/fr/guide/getting-started.md create mode 100644 docs/fr/guide/interactions.md create mode 100644 docs/fr/guide/listeners.md create mode 100644 docs/fr/guide/services.md create mode 100644 docs/fr/index.md diff --git a/docs/fr/guide/commands.md b/docs/fr/guide/commands.md new file mode 100644 index 0000000..5ba62d8 --- /dev/null +++ b/docs/fr/guide/commands.md @@ -0,0 +1,64 @@ +# Commandes + +Ce guide explique comment créer des commandes slash Discord dans vos modules. Les commandes ne sont disponibles que si le module est activé sur le serveur. + +## Création d'une commande + +```typescript +// src/modules/mon-module/commands/test.command.ts + +import { SlashCommandBuilder } from "discord.js"; +import { declareCommand } from "#lib/command.js"; + +export default declareCommand({ + data: new SlashCommandBuilder() + .setName("test") + .setDescription("Une commande de test"), + + async execute(interaction) { + await interaction.reply("Test !"); + }, +}); +``` + +## Interface Command + +```typescript +interface Command { + data: SlashCommandBuilder; // Configuration de la commande + execute: ( + interaction, + config? // Fonction d'exécution (obligatoire) + ) => Promise; + complete?: ( + interaction, + config? // Autocomplétion (optionnelle) + ) => Promise; +} +``` + +Le paramètre `config` est un `ConfigProvider` qui donne accès à la configuration du module (voir [Configuration](./configuration)). + +## Enregistrement dans le module + +```typescript +// src/modules/mon-module/mon-module.module.ts +import testCommand from "./commands/test.command.js"; + +export default defineModule({ + onLoad(_client, registry) { + registry.register(testCommand); + }, +}); +``` + +## Enregistrement et propagation + +| Commandes | Production | Développement (`NODE_ENV=development`) | +| -------------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| **core** (`/config`, `/modules`) | Globales (propagation ~1 h) | Enregistrées sur `DEV_GUILD_ID` — **instantané** | +| **module** | Par serveur, (ré)installées au changement de `version` du module | Re-synchronisées **à chaque démarrage** sur `DEV_GUILD_ID` pour les modules activés | + +En production, le versionnage évite de re-pousser les commandes d'un module sur toutes les guildes à chaque démarrage. En développement, les commandes sont enregistrées en un seul PUT sur la guild de développement, ce qui est instantané. + +> `DEV_GUILD_ID` est **requis** en mode développement. Voir `.env.example`. diff --git a/docs/fr/guide/configuration.md b/docs/fr/guide/configuration.md new file mode 100644 index 0000000..02b1a29 --- /dev/null +++ b/docs/fr/guide/configuration.md @@ -0,0 +1,153 @@ +# Configuration + +OmniBot fournit un système de configuration typée pour les modules. Chaque module peut déclarer un schéma de configuration qui est automatiquement exposé via une interface interactive Discord accessible aux administrateurs. + +## Déclarer un schéma de configuration + +Un module déclare son schéma dans `defineModule()` via la propriété `config` : + +```typescript +// src/modules/mon-module/mon-module.module.ts + +import { ConfigType } from "#lib/config.js"; +import { defineModule } from "#lib/module.js"; + +export default defineModule({ + id: "mon-module", + name: "Mon Module", + description: "Description de mon module.", + version: "1.0.0", + + config: { + logChannel: { + name: "Salon de logs", + description: "Salon où poster les logs", + type: ConfigType.CHANNEL, + }, + maxWarnings: { + name: "Avertissements max", + description: "Nombre d'avertissements avant sanction", + type: ConfigType.NUMBER, + defaultValue: 3, + }, + logLevel: { + name: "Niveau de log", + description: "Verbosité des logs", + type: ConfigType.ENUM, + options: ["debug", "info", "warn", "error"] as const, + defaultValue: "info", + }, + }, + + onLoad(_client, registry) { + // ... + }, +}); +``` + +## Types de champs supportés + +| Type | Saisie | Stockage (JSON) | Lecture | +| ---------- | ------------------------ | ---------------- | ----------------- | +| `STRING` | Modal (texte) | `string` | `string` | +| `NUMBER` | Modal (texte → nombre) | `number` | `number` | +| `BOOLEAN` | Bouton toggle | `boolean` | `boolean` | +| `USER` | Select menu utilisateur | `string` (id) | `User` | +| `ROLE` | Select menu rôle | `string` (id) | `Role` | +| `CHANNEL` | Select menu salon | `string` (id) | `Channel` | +| `CATEGORY` | Select menu catégorie | `string` (id) | `CategoryChannel` | +| `ENUM` | Select menu (choix fixe) | `string` (choix) | Union littérale | + +## Listes + +N'importe quel type peut être déclaré en **liste** via `type: [ConfigType.X]` : + +```typescript +config: { + channels: { + name: "Salons surveillés", + description: "Salons à surveiller (un ou plusieurs)", + type: [ConfigType.CHANNEL], // Liste de salons + }, + warnings: { + name: "Avertissements", + description: "Liste d'avertissements", + type: [ConfigType.NUMBER], // Liste de nombres + }, +} +``` + +Le type retourné par `config.get("channels")` est alors `Channel[]`. + +## Type ENUM (choix fixe) + +Le type `ENUM` permet de restreindre un champ à un ensemble fixe de valeurs : + +```typescript +config: { + theme: { + name: "Thème", + description: "Thème d'affichage", + type: ConfigType.ENUM, + options: ["clair", "sombre", "auto"] as const, + defaultValue: "auto", + }, + features: { + name: "Fonctionnalités", + description: "Fonctionnalités activées", + type: [ConfigType.ENUM], // Liste multi-choix + options: ["welcome", "logs", "automod"] as const, + }, +} +``` + +- `options` est **obligatoire** sur une entrée `ENUM` +- L'utilisation de `as const` donne un typage précis : `config.get("theme")` retourne `"clair" | "sombre" | "auto"` +- Sans `as const`, le type retourné est `string` + +## Valeurs par défaut + +- Un champ **avec** `defaultValue` est toujours présent (`T`) +- Un champ **sans** `defaultValue` peut être `undefined` (`T | undefined`) +- Les entités Discord sont automatiquement désérialisées (du stockage par id vers l'objet Discord) + +## Accès à la configuration + +La configuration est accessible via le paramètre `config` dans les commandes, écouteurs et interactions : + +```typescript +// Dans une commande +async execute(interaction, config) { + const channel = config.get("logChannel"); // Channel | undefined + const max = config.get("maxWarnings"); // number (a un defaultValue) + const level = config.get("logLevel"); // "debug" | "info" | "warn" | "error" +} +``` + +## Interface administrateur + +La commande `/config ` (réservée aux administrateurs) affiche un panneau de configuration interactif avec : + +- La liste de tous les champs configurables, leur type et valeur courante +- Des boutons d'édition adaptés à chaque type (modal, toggle, select menu) +- Une pagination automatique si le module a plus de 10 champs configurables +- Barre de navigation si plusieurs pages + +Les modifications sont persistées et prennent effet immédiatement. + +## Bonnes pratiques + +### Nommage des champs + +- **Clé** : camelCase (`logChannel`, `maxWarnings`) +- **name** : lisible, affiché dans l'interface (`Salon de logs`) +- **description** : explique le rôle du champ + +### Validation + +La validation est automatique selon le type déclaré. Pour `ENUM`, seules les valeurs listées dans `options` sont acceptées. + +## Prochaines étapes + +- [Services](./services) pour organiser la logique métier +- [Base de données](./database) pour des données persistantes avancées diff --git a/docs/fr/guide/creating-a-module.md b/docs/fr/guide/creating-a-module.md new file mode 100644 index 0000000..f8b8acf --- /dev/null +++ b/docs/fr/guide/creating-a-module.md @@ -0,0 +1,148 @@ +# Créer un module + +Un module dans OmniBot est une unité fonctionnelle autonome qui peut être installée et désinstallée par serveur Discord. Chaque module peut contenir des commandes, des écouteurs d'événements, des interactions et ses propres données. + +## Structure d'un module + +``` +src/modules/mon-module/ +├── mon-module.module.ts # Définition du module principal +├── commands/ # Commandes du module +│ └── ma-commande.command.ts +├── listeners/ # Écouteurs d'événements +│ └── mon-listener.listener.ts +├── interactions/ # Handlers d'interactions (boutons, etc.) +│ └── mon-bouton.button.ts +├── services/ # Services métier +│ └── mon-service.service.ts +└── models/ # Modèles Prisma (optionnel) + └── mon-modele.prisma +``` + +## Création d'un module + +### 1. Définition du module principal + +Créez le fichier principal de votre module : + +```typescript +// src/modules/mon-module/mon-module.module.ts + +import { GatewayIntentBits } from "discord.js"; +import { defineModule } from "#lib/module.js"; +import logger from "#lib/logger.js"; + +export default defineModule({ + id: "mon-module", + name: "Mon Module", + description: "Description de mon module personnalisé.", + version: "1.0.0", + author: "Votre Nom", // Optionnel + + // Intents Discord requis par le module + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + ], + + // Appelé au démarrage du bot + onLoad(_client, registry) { + // Enregistrer les commandes, listeners et interactions + // registry.register(maCommande); + // registry.register(monListener); + // registry.register(monInteraction); + + logger.info("Mon module chargé avec succès"); + }, + + // Appelé quand le module est installé sur un serveur + onInstall(_client, guild) { + logger.info(`Mon module installé sur ${guild.name}`); + }, + + // Appelé quand le module est désinstallé d'un serveur + onUninstall(_client, guild) { + logger.info(`Mon module désinstallé de ${guild.name}`); + }, +}); +``` + +### 2. Cycles de vie + +Un module expose trois hooks : + +| Hook | Quand | Usage | +| ------------- | ---------------------------- | -------------------------------------------------- | +| `onLoad` | Au démarrage du bot | Enregistrer commandes, listeners, interactions | +| `onInstall` | Installation sur un serveur | Créer des rôles, initialiser des données | +| `onUninstall` | Désinstallation d'un serveur | Nettoyer des données, supprimer des configurations | + +### 3. Interface ModuleDeclaration + +```typescript +interface ModuleDeclaration { + id: string; // Identifiant unique (kebab-case) + name: string; // Nom d'affichage + description: string; // Description + version: string; // Version semver (ex: "1.0.0") + author?: string; // Auteur (optionnel) + intents?: GatewayIntentBits[]; // Intents Discord requis + devOnly?: boolean; // Chargé seulement en mode développement + config?: ConfigSchema; // Schéma de configuration (voir Configuration) + + onLoad: (client, registry) => void; + onInstall: (client, guild, registry) => void; + onUninstall: (client, guild, registry) => void; +} +``` + +## Bonnes pratiques + +### Conventions de nommage + +- **ID du module** : kebab-case (`mon-super-module`) +- **Nom du fichier** : `{id}.module.ts` +- **Dossier** : même nom que l'ID du module + +### Gestion des intents + +Déclarez uniquement les intents nécessaires à votre module. Consultez la [documentation Discord](https://discord.com/developers/docs/events/gateway#list-of-intents) pour savoir quels intents sont requis. + +### Gestion des erreurs + +```typescript +onInstall(_client, guild) { + try { + // Logique d'installation + } catch (error) { + logger.error(`Erreur lors de l'installation : ${error.message}`); + } +} +``` + +### Organisation des fichiers + +- Gardez le fichier principal du module léger +- Séparez la logique complexe dans des services +- Utilisez des sous-dossiers pour organiser commandes, listeners et interactions + +## Découverte automatique + +Les modules sont chargés automatiquement depuis `src/modules/` au démarrage. Le chargeur (`module-loader.ts`) : + +1. Parcourt chaque sous-dossier de `src/modules/` +2. Cherche un fichier `*.module.ts` (ou `*.module.js`) +3. Importe le module et vérifie qu'il expose un `default` de type `Module` +4. Ignore les modules marqués `devOnly: true` en production + +Aucun enregistrement manuel n'est nécessaire. + +## Prochaines étapes + +- [Commandes](./commands) — Ajouter des commandes slash à votre module +- [Écouteurs](./listeners) — Réagir aux événements Discord +- [Interactions](./interactions) — Boutons, modales et menus déroulants +- [Configuration](./configuration) — Déclarer un schéma de configuration +- [Services](./services) — Organiser la logique métier +- [Base de données](./database) — Utiliser Prisma avec votre module diff --git a/docs/fr/guide/database.md b/docs/fr/guide/database.md new file mode 100644 index 0000000..f2300a8 --- /dev/null +++ b/docs/fr/guide/database.md @@ -0,0 +1,118 @@ +# Base de données + +OmniBot utilise Prisma comme ORM avec une architecture multi-fichiers qui permet de distribuer les modèles de base de données à travers les différents modules. + +## Architecture + +### Structure des fichiers Prisma + +``` +src/ +├── prisma/ +│ ├── dbinfo.prisma # Configuration du générateur et datasource +│ └── schema.prisma # Schéma consolidé (généré) +├── core/ +│ └── models/ +│ └── modules.prisma # Modèles du système de modules +└── modules/ + └── [module-name]/ + └── models/ + └── *.prisma # Modèles spécifiques au module +``` + +### Configuration + +Le fichier `dbinfo.prisma` contient la configuration de base : + +```prisma +generator client { + provider = "prisma-client-js" + output = "../src/generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +## Ajouter un modèle à votre module + +1. Créez un fichier `.prisma` dans le dossier `models/` de votre module : + +``` +src/modules/mon-module/models/mon-modele.prisma +``` + +2. Définissez votre modèle : + +```prisma +model MonModele { + id String @id @default(cuid()) + nom String + createdAt DateTime @default(now()) +} +``` + +3. Générez le client Prisma : + +```bash +pnpm prisma:generate +``` + +4. Créez une migration : + +```bash +pnpm prisma:migrate +``` + +## Système de consolidation + +Au lieu d'avoir tous les modèles dans un seul fichier `schema.prisma`, le projet permet de distribuer les modèles dans différents fichiers `.prisma` à travers les modules. Un script de consolidation (`scripts/consolidate-schema.ts`) rassemble automatiquement tous ces fichiers avec le header `dbinfo.prisma` dans le schéma principal. + +Le script : + +1. Parcourt tous les dossiers dans `src/` pour trouver les fichiers `.prisma` (sauf dans `src/prisma/`) +2. Combine le header et tous les modèles dans un seul `schema.prisma` +3. Ajoute des commentaires pour identifier la source de chaque modèle + +### Scripts npm + +```bash +pnpm prisma:consolidate # Consolide uniquement les modèles +pnpm prisma:generate # Consolide + génère le client Prisma +pnpm prisma:migrate # Consolide + crée/applique une migration +pnpm prisma:studio # Consolide + ouvre Prisma Studio +``` + +## Utilisation dans le code + +```typescript +import prisma from "#lib/database.js"; + +// Dans un service ou une commande +const users = await prisma.user.findMany(); +const newUser = await prisma.user.create({ + data: { userId: "123", username: "test" }, +}); +``` + +## Bonnes pratiques + +- **Modèles du core** : `src/core/models/` +- **Modèles spécifiques aux modules** : `src/modules/[module-name]/models/` +- **Nommage des fichiers** : `nom-descriptif.prisma` +- **Nommage des modèles** : PascalCase (`ModuleActivation`) +- **Nommage des champs** : camelCase (`moduleId`) +- Réduisez le nombre de modèles par fichier pour faciliter la maintenance + +## Variables d'environnement + +```ini +DATABASE_URL="postgresql://username:password@localhost:5432/omnibot" +``` + +## Ressources utiles + +- [Documentation Prisma](https://www.prisma.io/docs/) +- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference) diff --git a/docs/fr/guide/getting-started.md b/docs/fr/guide/getting-started.md new file mode 100644 index 0000000..21b93b3 --- /dev/null +++ b/docs/fr/guide/getting-started.md @@ -0,0 +1,73 @@ +# Pour commencer + +Bienvenue dans le guide de développement d'OmniBot ! Cette documentation vous explique comment créer des modules, commandes et écouteurs pour étendre les fonctionnalités du bot Discord. + +OmniBot est un bot Discord modulaire où chaque fonctionnalité est encapsulée dans son propre module. Les modules sont auto-découverts au démarrage — **aucun enregistrement manuel n'est nécessaire** en dehors du dossier du module. + +## Architecture du projet + +``` +src/ +├── modules/ # Dossier contenant tous les modules du bot +│ ├── mon-module/ # Module +│ │ ├── commands/ # Commandes du module +│ │ ├── listeners/ # Écouteurs du module +│ │ ├── models/ # Modèles Prisma (optionnel) +│ │ ├── services/ # Services du module +│ │ ├── interactions/ # Handlers d'interactions (boutons, etc.) +│ │ └── mon-module.module.ts # Fichier principal du module +├── lib/ # Bibliothèque exposée aux modules +│ ├── module.ts # defineModule() +│ ├── command.ts # declareCommand() +│ ├── listener.ts # declareEventListener() +│ ├── interaction.ts # declareInteractionHandler() +│ ├── service.ts # declareService() +│ ├── config.ts # ConfigType, ConfigProvider +│ ├── database.ts # Client Prisma +│ └── logger.ts # Logger structuré +├── core/ # Système central du bot +│ ├── commands/ # Commandes système (/modules, /config) +│ ├── loaders/ # Chargeurs de modules/commandes +│ └── services/ # Services internes +└── prisma/ # Configuration Prisma + ├── dbinfo.prisma # Configuration générateur + datasource + └── schema.prisma # Schéma consolidé (généré automatiquement) +``` + +## Conventions de nommage + +Le projet utilise un système de suffixes pour identifier le rôle de chaque fichier : + +- `*.module.ts` — Définition du module (ex: `mon-module.module.ts`) +- `*.command.ts` — Commande slash (ex: `test.command.ts`) +- `*.listener.ts` — Écouteur d'événement (ex: `message-create.listener.ts`) +- `*.button.ts` / `*.modal.ts` / `*.select.ts` — Handlers d'interactions +- `*.service.ts` — Service métier (ex: `user.service.ts`) +- `*.prisma` — Modèle de base de données (ex: `users.prisma`) + +## Imports + +Les imports entre modules se font via des **subpath imports** avec `#lib/...` : + +```typescript +import { defineModule } from "#lib/module.js"; +import { declareCommand } from "#lib/command.js"; +import { declareEventListener } from "#lib/listener.js"; +import { declareInteractionHandler } from "#lib/interaction.js"; +import { declareService } from "#lib/service.js"; +import { ConfigType } from "#lib/config.js"; +import logger from "#lib/logger.js"; +import prisma from "#lib/database.js"; +``` + +Les imports dans un même répertoire restent relatifs (`./fichier.js`). L'extension `.js` est toujours présente (NodeNext). + +## Prochaines étapes + +- [Créer un module](./creating-a-module) — Structure et cycle de vie d'un module +- [Commandes](./commands) — Créer des commandes slash +- [Écouteurs](./listeners) — Réagir aux événements Discord +- [Interactions](./interactions) — Boutons, menus déroulants et modales +- [Configuration](./configuration) — Schéma de configuration typé +- [Services](./services) — Logique métier +- [Base de données](./database) — Prisma ORM diff --git a/docs/fr/guide/interactions.md b/docs/fr/guide/interactions.md new file mode 100644 index 0000000..1e17d31 --- /dev/null +++ b/docs/fr/guide/interactions.md @@ -0,0 +1,205 @@ +# Interactions + +Les interactions Discord permettent à votre module de réagir aux actions des utilisateurs sur des composants d'interface : boutons, menus déroulants et modales. + +## Types d'interactions supportées + +OmniBot supporte deux types d'interactions : + +- **Message Component Interactions** : boutons, menus déroulants (select menus) +- **Modal Submit Interactions** : soumissions de formulaires modaux + +## Structure des fichiers + +``` +src/modules/mon-module/ +├── mon-module.module.ts +├── commands/ +│ └── ma-commande.command.ts +└── interactions/ + ├── mon-bouton.button.ts + ├── mon-menu.select.ts + └── ma-modale.modal.ts +``` + +## API + +```typescript +interface InteractionHandler { + customId: string; // Identifiant unique + requiresAdmin?: boolean; // Réservé aux admins + check: (interaction) => interaction is T; // Vérification du type + execute: (interaction, args[], config?) // Fonction d'exécution + => Promise; +} +``` + +Le paramètre `config` est un `ConfigProvider` qui donne accès à la configuration du module (voir [Configuration](./configuration)). + +Le paramètre `requiresAdmin` permet de réserver l'interaction aux administrateurs du serveur. La vérification est faite centralement par le système — aucun code supplémentaire n'est nécessaire. + +## Création d'une interaction + +### Bouton + +```typescript +// src/modules/mon-module/interactions/confirm.button.ts + +import { MessageFlags } from "discord.js"; +import { declareInteractionHandler } from "#lib/interaction.js"; + +export default declareInteractionHandler({ + customId: "confirm-action", + check: (interaction) => interaction.isButton(), + + async execute(interaction, [actionId, userId]) { + await interaction.reply({ + content: `Action ${actionId} confirmée pour l'utilisateur ${userId}`, + flags: MessageFlags.Ephemeral, + }); + }, +}); +``` + +### Menu déroulant + +```typescript +// src/modules/mon-module/interactions/role-select.select.ts + +import { declareInteractionHandler } from "#lib/interaction.js"; + +export default declareInteractionHandler({ + customId: "role-select", + check: (interaction) => interaction.isStringSelectMenu(), + + async execute(interaction, [targetUserId]) { + const selectedRoles = interaction.values; + + await interaction.reply({ + content: `Rôles ${selectedRoles.join(", ")} attribués à <@${targetUserId}>`, + ephemeral: true, + }); + }, +}); +``` + +### Modal + +```typescript +// src/modules/mon-module/interactions/feedback.modal.ts + +import { declareInteractionHandler } from "#lib/interaction.js"; + +export default declareInteractionHandler({ + customId: "feedback-modal", + check: (interaction) => interaction.isModalSubmit(), + + async execute(interaction, [category]) { + const feedback = interaction.fields.getTextInputValue("feedback-input"); + + await interaction.reply({ + content: "Merci pour votre retour !", + ephemeral: true, + }); + }, +}); +``` + +## Système de Custom ID avec arguments + +Le système permet de passer des arguments via le `customId` en utilisant le séparateur `:` : + +``` +customId:arg1:arg2:arg3 +``` + +### Utilisation dans une commande + +```typescript +import { ButtonBuilder, ButtonStyle } from "discord.js"; + +const button = new ButtonBuilder() + .setCustomId(`confirm-action:delete:${userId}`) + .setLabel("Confirmer") + .setStyle(ButtonStyle.Danger); +``` + +Les arguments sont automatiquement extraits et passés au handler sous forme de tableau (`args`). + +## Enregistrement dans le module + +```typescript +// src/modules/mon-module/mon-module.module.ts +import confirmButton from "./interactions/confirm.button.js"; +import roleSelect from "./interactions/role-select.select.js"; + +export default defineModule({ + onLoad(_client, registry) { + registry.register(confirmButton); + registry.register(roleSelect); + }, +}); +``` + +## Gestion automatique de l'activation + +Le système gère automatiquement l'activation et la désactivation des interactions : + +- Les interactions ne fonctionnent que si le module est activé sur le serveur +- Aucun code supplémentaire nécessaire pour vérifier l'état du module +- Messages d'erreur automatiques si le module est désactivé +- Les interactions marquées `requiresAdmin: true` sont protégées automatiquement + +## Bonnes pratiques + +### Validation des arguments + +```typescript +async execute(interaction, [userId, action]) { + if (!userId || !action) { + await interaction.reply({ + content: "Données manquantes. Veuillez réessayer.", + ephemeral: true, + }); + return; + } +} +``` + +### Gestion des erreurs + +```typescript +async execute(interaction, [targetId]) { + try { + await performRiskyOperation(targetId); + await interaction.reply({ content: "Opération réussie !", ephemeral: true }); + } catch (error) { + logger.error("Erreur:", error); + await interaction.reply({ + content: "Une erreur s'est produite.", + ephemeral: true, + }); + } +} +``` + +### Types de réponses + +```typescript +// Action instantanée +await interaction.reply({ content: "Fait !", ephemeral: true }); + +// Action longue +await interaction.deferReply({ ephemeral: true }); +await longOperation(); +await interaction.editReply({ content: "Terminé !" }); + +// Mise à jour du message (boutons) +await interaction.update({ content: "Mis à jour", components: [] }); +``` + +## Prochaines étapes + +- [Configuration](./configuration) pour gérer les paramètres du module +- [Commandes](./commands) pour créer des commandes slash +- [Écouteurs](./listeners) pour réagir aux événements Discord diff --git a/docs/fr/guide/listeners.md b/docs/fr/guide/listeners.md new file mode 100644 index 0000000..5d5dfa1 --- /dev/null +++ b/docs/fr/guide/listeners.md @@ -0,0 +1,44 @@ +# Écouteurs + +Les écouteurs d'événements (listeners) permettent à votre module de réagir aux événements Discord. Le système de modules gère automatiquement l'activation/désactivation des écouteurs selon l'état du module. + +> **Important** : Pour les événements pouvant se produire en messages privés, vous devez gérer manuellement la vérification d'activation du module, car le système ne peut pas détecter automatiquement si le module est actif en dehors d'un serveur. + +> **Intents Discord** : Assurez-vous d'ajouter les intents nécessaires dans `defineModule()` et dans votre configuration Discord Developer Portal. + +## Déclaration d'un écouteur + +```typescript +// src/modules/mon-module/listeners/message-create.listener.ts + +import { declareEventListener } from "#lib/listener.js"; + +export default declareEventListener({ + eventType: "messageCreate", + + async execute(message, config) { + // config est un ConfigProvider | undefined + // Votre logique ici + }, +}); +``` + +## Enregistrement dans le module + +```typescript +// src/modules/mon-module/mon-module.module.ts +import messageListener from "./listeners/message-create.listener.js"; + +export default defineModule({ + onLoad(_client, registry) { + registry.register(messageListener); + }, +}); +``` + +Le système active ou désactive automatiquement l'écouteur selon que le module est installé sur le serveur concerné. + +## Prochaines étapes + +- [Configuration](./configuration) pour gérer les paramètres du module +- [Base de données](./database) pour les données persistantes diff --git a/docs/fr/guide/services.md b/docs/fr/guide/services.md new file mode 100644 index 0000000..ed61176 --- /dev/null +++ b/docs/fr/guide/services.md @@ -0,0 +1,53 @@ +# Services + +Les services permettent d'encapsuler la logique métier et de la réutiliser à travers votre module. + +## Création d'un service + +```typescript +// src/modules/mon-module/services/user.service.ts + +import { declareService, type Service } from "#lib/service.js"; +import prisma from "#lib/database.js"; + +class UserService implements Service { + async createUser(userId: string, username: string) { + return await prisma.user.create({ + data: { userId, username }, + }); + } + + async getUser(userId: string) { + return await prisma.user.findUnique({ + where: { userId }, + }); + } +} + +export default declareService(new UserService()); +``` + +## Interface Service + +La fonction `declareService` accepte n'importe quelle instance de classe. L'interface `Service` est pour l'instant vide, ce qui permet une grande flexibilité dans la structure de vos services. + +## Utilisation + +Les services s'importent et s'utilisent dans vos commandes, écouteurs ou autres services : + +```typescript +// Dans une commande +import userService from "../services/user.service.js"; + +async execute(interaction) { + const user = await userService.getUser(interaction.user.id); + // ... +} +``` + +## Bonnes pratiques + +- Utilisez les services pour encapsuler la logique métier complexe +- Gardez les services focalisés sur une responsabilité spécifique +- Utilisez les services pour les interactions avec la base de données +- Exportez toujours une instance déclarée avec `declareService` diff --git a/docs/fr/index.md b/docs/fr/index.md new file mode 100644 index 0000000..816b540 --- /dev/null +++ b/docs/fr/index.md @@ -0,0 +1,29 @@ +--- +layout: home + +hero: + name: OmniBot + text: Bot Discord modulaire + tagline: Documentation pour créer et étendre les fonctionnalités du bot. + actions: + - theme: brand + text: Commencer + link: /fr/guide/getting-started + - theme: alt + text: Créer un module + link: /fr/guide/creating-a-module + +features: + - icon: 🧩 + title: Modules autonomes + details: Chaque fonctionnalité est un module indépendant, installable par serveur. + - icon: ⚡ + title: Commandes slash + details: Créez des commandes slash typées avec autocomplétion. + - icon: 🔔 + title: Écouteurs d'événements + details: Réagissez aux événements Discord avec activation automatique par module. + - icon: 🎛️ + title: Configuration typée + details: Déclarez un schéma de configuration et obtenez une UI interactive. +--- From d70204c7ee8ce5afcdb58ad59e2671fc01661c2f Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:26:37 +0200 Subject: [PATCH 04/14] docs(en): add English documentation pages - Add landing page with feature overview - Add getting-started, module, commands, listeners guides - Add interactions, configuration, services, database guides --- docs/en/guide/commands.md | 64 +++++++++ docs/en/guide/configuration.md | 153 +++++++++++++++++++++ docs/en/guide/creating-a-module.md | 146 ++++++++++++++++++++ docs/en/guide/database.md | 118 +++++++++++++++++ docs/en/guide/getting-started.md | 73 ++++++++++ docs/en/guide/interactions.md | 205 +++++++++++++++++++++++++++++ docs/en/guide/listeners.md | 44 +++++++ docs/en/guide/services.md | 53 ++++++++ docs/en/index.md | 29 ++++ 9 files changed, 885 insertions(+) create mode 100644 docs/en/guide/commands.md create mode 100644 docs/en/guide/configuration.md create mode 100644 docs/en/guide/creating-a-module.md create mode 100644 docs/en/guide/database.md create mode 100644 docs/en/guide/getting-started.md create mode 100644 docs/en/guide/interactions.md create mode 100644 docs/en/guide/listeners.md create mode 100644 docs/en/guide/services.md create mode 100644 docs/en/index.md diff --git a/docs/en/guide/commands.md b/docs/en/guide/commands.md new file mode 100644 index 0000000..1d0a88a --- /dev/null +++ b/docs/en/guide/commands.md @@ -0,0 +1,64 @@ +# Commands + +This guide explains how to create Discord slash commands in your modules. Commands are only available when the module is enabled on the guild. + +## Creating a command + +```typescript +// src/modules/my-module/commands/test.command.ts + +import { SlashCommandBuilder } from "discord.js"; +import { declareCommand } from "#lib/command.js"; + +export default declareCommand({ + data: new SlashCommandBuilder() + .setName("test") + .setDescription("A test command"), + + async execute(interaction) { + await interaction.reply("Test!"); + }, +}); +``` + +## Command interface + +```typescript +interface Command { + data: SlashCommandBuilder; // Command configuration + execute: ( + interaction, + config? // Execution function (required) + ) => Promise; + complete?: ( + interaction, + config? // Autocomplete (optional) + ) => Promise; +} +``` + +The `config` parameter is a `ConfigProvider` giving access to the module's configuration (see [Configuration](./configuration)). + +## Registering in the module + +```typescript +// src/modules/my-module/my-module.module.ts +import testCommand from "./commands/test.command.js"; + +export default defineModule({ + onLoad(_client, registry) { + registry.register(testCommand); + }, +}); +``` + +## Registration & propagation + +| Commands | Production | Development (`NODE_ENV=development`) | +| -------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------- | +| **core** (`/config`, `/modules`) | Global (~1 h propagation) | Registered on `DEV_GUILD_ID` — **instant** | +| **module** | Per guild, (re)installed on module `version` bump | Re-synced **at every startup** on `DEV_GUILD_ID` for enabled modules | + +In production, version gating prevents re-pushing module commands to all guilds on every startup. In development, all commands are registered in a single PUT on the dev guild for instant updates. + +> `DEV_GUILD_ID` is **required** in development mode. See `.env.example`. diff --git a/docs/en/guide/configuration.md b/docs/en/guide/configuration.md new file mode 100644 index 0000000..f535961 --- /dev/null +++ b/docs/en/guide/configuration.md @@ -0,0 +1,153 @@ +# Configuration + +OmniBot provides a typed configuration system for modules. Each module can declare a configuration schema that is automatically exposed through an interactive Discord interface accessible to administrators. + +## Declaring a configuration schema + +A module declares its schema in `defineModule()` via the `config` property: + +```typescript +// src/modules/my-module/my-module.module.ts + +import { ConfigType } from "#lib/config.js"; +import { defineModule } from "#lib/module.js"; + +export default defineModule({ + id: "my-module", + name: "My Module", + description: "Description of my module.", + version: "1.0.0", + + config: { + logChannel: { + name: "Log channel", + description: "Channel where to post logs", + type: ConfigType.CHANNEL, + }, + maxWarnings: { + name: "Max warnings", + description: "Number of warnings before action", + type: ConfigType.NUMBER, + defaultValue: 3, + }, + logLevel: { + name: "Log level", + description: "Log verbosity", + type: ConfigType.ENUM, + options: ["debug", "info", "warn", "error"] as const, + defaultValue: "info", + }, + }, + + onLoad(_client, registry) { + // ... + }, +}); +``` + +## Supported field types + +| Type | Input | Storage (JSON) | Read | +| ---------- | --------------------- | ----------------- | ----------------- | +| `STRING` | Modal (text) | `string` | `string` | +| `NUMBER` | Modal (text → number) | `number` | `number` | +| `BOOLEAN` | Toggle button | `boolean` | `boolean` | +| `USER` | User select menu | `string` (id) | `User` | +| `ROLE` | Role select menu | `string` (id) | `Role` | +| `CHANNEL` | Channel select menu | `string` (id) | `Channel` | +| `CATEGORY` | Category select menu | `string` (id) | `CategoryChannel` | +| `ENUM` | Select menu (choices) | `string` (choice) | Literal union | + +## Lists + +Any type can be declared as a **list** using `type: [ConfigType.X]`: + +```typescript +config: { + channels: { + name: "Monitored channels", + description: "Channels to monitor (one or more)", + type: [ConfigType.CHANNEL], // Channel list + }, + warnings: { + name: "Warnings", + description: "List of warnings", + type: [ConfigType.NUMBER], // Number list + }, +} +``` + +The returned type of `config.get("channels")` is `Channel[]`. + +## ENUM type (fixed choices) + +The `ENUM` type restricts a field to a fixed set of values: + +```typescript +config: { + theme: { + name: "Theme", + description: "Display theme", + type: ConfigType.ENUM, + options: ["light", "dark", "auto"] as const, + defaultValue: "auto", + }, + features: { + name: "Features", + description: "Enabled features", + type: [ConfigType.ENUM], // Multi-select list + options: ["welcome", "logs", "automod"] as const, + }, +} +``` + +- `options` is **required** on an `ENUM` entry +- Using `as const` gives precise typing: `config.get("theme")` returns `"light" | "dark" | "auto"` +- Without `as const`, the returned type is `string` + +## Default values + +- A field **with** `defaultValue` is always present (`T`) +- A field **without** `defaultValue` may be `undefined` (`T | undefined`) +- Discord entities are automatically deserialized (stored as id, read as Discord objects) + +## Accessing configuration + +Configuration is accessible via the `config` parameter in commands, listeners, and interactions: + +```typescript +// In a command +async execute(interaction, config) { + const channel = config.get("logChannel"); // Channel | undefined + const max = config.get("maxWarnings"); // number (has defaultValue) + const level = config.get("logLevel"); // "debug" | "info" | "warn" | "error" +} +``` + +## Admin interface + +The `/config ` command (admin-only) displays an interactive configuration panel featuring: + +- All configurable fields with their type and current value +- Edit buttons adapted to each type (modal, toggle, select menu) +- Automatic pagination if the module has more than 10 fields +- Navigation bar when multiple pages + +Changes are persisted and take effect immediately. + +## Best practices + +### Field naming + +- **Key**: camelCase (`logChannel`, `maxWarnings`) +- **name**: human-readable, shown in the UI (`Log channel`) +- **description**: explains the field's purpose + +### Validation + +Validation is automatic based on the declared type. For `ENUM`, only values listed in `options` are accepted. + +## Next steps + +- [Services](./services) for organizing business logic +- [Database](./database) for advanced persistent data diff --git a/docs/en/guide/creating-a-module.md b/docs/en/guide/creating-a-module.md new file mode 100644 index 0000000..3ae7543 --- /dev/null +++ b/docs/en/guide/creating-a-module.md @@ -0,0 +1,146 @@ +# Creating a Module + +A module in OmniBot is a self-contained functional unit that can be installed and uninstalled per Discord guild. Each module can contain commands, event listeners, interactions, and its own data. + +## Module structure + +``` +src/modules/my-module/ +├── my-module.module.ts # Main module definition +├── commands/ # Module commands +│ └── my-command.command.ts +├── listeners/ # Event listeners +│ └── my-listener.listener.ts +├── interactions/ # Interaction handlers (buttons, etc.) +│ └── my-button.button.ts +├── services/ # Business services +│ └── my-service.service.ts +└── models/ # Prisma models (optional) + └── my-model.prisma +``` + +## Creating a module + +### 1. Define the main module file + +```typescript +// src/modules/my-module/my-module.module.ts + +import { GatewayIntentBits } from "discord.js"; +import { defineModule } from "#lib/module.js"; +import logger from "#lib/logger.js"; + +export default defineModule({ + id: "my-module", + name: "My Module", + description: "Description of my custom module.", + version: "1.0.0", + author: "Your Name", // Optional + + // Discord intents required by the module + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + ], + + // Called at bot startup + onLoad(_client, registry) { + // Register commands, listeners, and interactions + // registry.register(myCommand); + // registry.register(myListener); + // registry.register(myInteraction); + + logger.info("My module loaded successfully"); + }, + + // Called when the module is installed on a guild + onInstall(_client, guild) { + logger.info(`My module installed on ${guild.name}`); + }, + + // Called when the module is uninstalled from a guild + onUninstall(_client, guild) { + logger.info(`My module uninstalled from ${guild.name}`); + }, +}); +``` + +### 2. Lifecycle hooks + +A module exposes three hooks: + +| Hook | When | Usage | +| ------------- | -------------------- | ------------------------------------------ | +| `onLoad` | Bot startup | Register commands, listeners, interactions | +| `onInstall` | Guild installation | Create roles, initialize data | +| `onUninstall` | Guild uninstallation | Clean up data, remove configurations | + +### 3. ModuleDeclaration interface + +```typescript +interface ModuleDeclaration { + id: string; // Unique identifier (kebab-case) + name: string; // Display name + description: string; // Description + version: string; // Semver version (e.g. "1.0.0") + author?: string; // Author (optional) + intents?: GatewayIntentBits[]; // Required Discord intents + devOnly?: boolean; // Only loaded in dev mode + config?: ConfigSchema; // Configuration schema (see Configuration) + + onLoad: (client, registry) => void; + onInstall: (client, guild, registry) => void; + onUninstall: (client, guild, registry) => void; +} +``` + +## Best practices + +### Naming conventions + +- **Module ID**: kebab-case (`my-super-module`) +- **File name**: `{id}.module.ts` +- **Directory**: same as module ID + +### Intent management + +Only declare the intents your module actually needs. See the [Discord documentation](https://discord.com/developers/docs/events/gateway#list-of-intents) for which intents are required. + +### Error handling + +```typescript +onInstall(_client, guild) { + try { + // Installation logic + } catch (error) { + logger.error(`Installation error: ${error.message}`); + } +} +``` + +### File organization + +- Keep the main module file lightweight +- Move complex logic to services +- Use subdirectories to organize commands, listeners, and interactions + +## Auto-discovery + +Modules are automatically loaded from `src/modules/` at startup. The loader (`module-loader.ts`): + +1. Iterates over each subdirectory in `src/modules/` +2. Looks for a `*.module.ts` (or `*.module.js`) file +3. Imports the module and validates it exposes a `Module`-typed default export +4. Skips modules marked `devOnly: true` in production + +No manual registration is needed. + +## Next steps + +- [Commands](./commands) — Add slash commands to your module +- [Listeners](./listeners) — React to Discord events +- [Interactions](./interactions) — Buttons, modals, and select menus +- [Configuration](./configuration) — Declare a configuration schema +- [Services](./services) — Organize business logic +- [Database](./database) — Use Prisma with your module diff --git a/docs/en/guide/database.md b/docs/en/guide/database.md new file mode 100644 index 0000000..4c5c229 --- /dev/null +++ b/docs/en/guide/database.md @@ -0,0 +1,118 @@ +# Database + +OmniBot uses Prisma as its ORM with a multi-file architecture that distributes database models across different modules. + +## Architecture + +### Prisma file structure + +``` +src/ +├── prisma/ +│ ├── dbinfo.prisma # Generator and datasource configuration +│ └── schema.prisma # Consolidated schema (generated) +├── core/ +│ └── models/ +│ └── modules.prisma # Core module system models +└── modules/ + └── [module-name]/ + └── models/ + └── *.prisma # Module-specific models +``` + +### Configuration + +The `dbinfo.prisma` file contains the base configuration: + +```prisma +generator client { + provider = "prisma-client-js" + output = "../src/generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} +``` + +## Adding a model to your module + +1. Create a `.prisma` file in your module's `models/` directory: + +``` +src/modules/my-module/models/my-model.prisma +``` + +2. Define your model: + +```prisma +model MyModel { + id String @id @default(cuid()) + name String + createdAt DateTime @default(now()) +} +``` + +3. Generate the Prisma client: + +```bash +pnpm prisma:generate +``` + +4. Create a migration: + +```bash +pnpm prisma:migrate +``` + +## Consolidation system + +Instead of keeping all models in a single `schema.prisma` file, the project distributes models across `.prisma` files in different modules. A consolidation script (`scripts/consolidate-schema.ts`) automatically merges all these files with the `dbinfo.prisma` header into the main schema. + +The script: + +1. Recursively scans all directories in `src/` for `.prisma` files (except `src/prisma/`) +2. Combines the header and all models into a single `schema.prisma` +3. Adds comments identifying each model's source + +### npm scripts + +```bash +pnpm prisma:consolidate # Consolidate models only +pnpm prisma:generate # Consolidate + generate Prisma client +pnpm prisma:migrate # Consolidate + create/apply migration +pnpm prisma:studio # Consolidate + open Prisma Studio +``` + +## Usage in code + +```typescript +import prisma from "#lib/database.js"; + +// In a service or command +const users = await prisma.user.findMany(); +const newUser = await prisma.user.create({ + data: { userId: "123", username: "test" }, +}); +``` + +## Best practices + +- **Core models**: `src/core/models/` +- **Module-specific models**: `src/modules/[module-name]/models/` +- **File naming**: `descriptive-name.prisma` +- **Model naming**: PascalCase (`ModuleActivation`) +- **Field naming**: camelCase (`moduleId`) +- Keep few models per file for easier maintenance + +## Environment variables + +```ini +DATABASE_URL="postgresql://username:password@localhost:5432/omnibot" +``` + +## Useful resources + +- [Prisma Documentation](https://www.prisma.io/docs/) +- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference) diff --git a/docs/en/guide/getting-started.md b/docs/en/guide/getting-started.md new file mode 100644 index 0000000..5fc3e28 --- /dev/null +++ b/docs/en/guide/getting-started.md @@ -0,0 +1,73 @@ +# Getting Started + +Welcome to the OmniBot development guide! This documentation explains how to create modules, commands, and listeners to extend the Discord bot's functionality. + +OmniBot is a modular Discord bot where each feature is encapsulated in its own module. Modules are auto-discovered at startup — **no manual registration is needed** outside the module directory. + +## Project structure + +``` +src/ +├── modules/ # All bot modules +│ ├── my-module/ # Module +│ │ ├── commands/ # Module commands +│ │ ├── listeners/ # Module listeners +│ │ ├── models/ # Prisma models (optional) +│ │ ├── services/ # Module services +│ │ ├── interactions/ # Interaction handlers (buttons, etc.) +│ │ └── my-module.module.ts # Main module file +├── lib/ # Library exposed to modules +│ ├── module.ts # defineModule() +│ ├── command.ts # declareCommand() +│ ├── listener.ts # declareEventListener() +│ ├── interaction.ts # declareInteractionHandler() +│ ├── service.ts # declareService() +│ ├── config.ts # ConfigType, ConfigProvider +│ ├── database.ts # Prisma client +│ └── logger.ts # Structured logger +├── core/ # Bot core system +│ ├── commands/ # System commands (/modules, /config) +│ ├── loaders/ # Module/command loaders +│ └── services/ # Internal services +└── prisma/ # Prisma configuration + ├── dbinfo.prisma # Generator + datasource config + └── schema.prisma # Consolidated schema (auto-generated) +``` + +## Naming conventions + +The project uses suffixes to identify each file's role: + +- `*.module.ts` — Module definition (e.g. `my-module.module.ts`) +- `*.command.ts` — Slash command (e.g. `test.command.ts`) +- `*.listener.ts` — Event listener (e.g. `message-create.listener.ts`) +- `*.button.ts` / `*.modal.ts` / `*.select.ts` — Interaction handlers +- `*.service.ts` — Business service (e.g. `user.service.ts`) +- `*.prisma` — Database model (e.g. `users.prisma`) + +## Imports + +Cross-directory imports use **subpath imports** with `#lib/...`: + +```typescript +import { defineModule } from "#lib/module.js"; +import { declareCommand } from "#lib/command.js"; +import { declareEventListener } from "#lib/listener.js"; +import { declareInteractionHandler } from "#lib/interaction.js"; +import { declareService } from "#lib/service.js"; +import { ConfigType } from "#lib/config.js"; +import logger from "#lib/logger.js"; +import prisma from "#lib/database.js"; +``` + +Same-directory imports stay relative (`./file.js`). The `.js` extension is always required (NodeNext). + +## Next steps + +- [Creating a Module](./creating-a-module) — Module structure and lifecycle +- [Commands](./commands) — Creating slash commands +- [Listeners](./listeners) — Reacting to Discord events +- [Interactions](./interactions) — Buttons, select menus, and modals +- [Configuration](./configuration) — Typed configuration schema +- [Services](./services) — Business logic +- [Database](./database) — Prisma ORM diff --git a/docs/en/guide/interactions.md b/docs/en/guide/interactions.md new file mode 100644 index 0000000..876ab5b --- /dev/null +++ b/docs/en/guide/interactions.md @@ -0,0 +1,205 @@ +# Interactions + +Discord interactions allow your module to react to user actions on UI components: buttons, select menus, and modals. + +## Supported interaction types + +OmniBot supports two types of interactions: + +- **Message Component Interactions**: buttons, select menus +- **Modal Submit Interactions**: form submissions + +## File structure + +``` +src/modules/my-module/ +├── my-module.module.ts +├── commands/ +│ └── my-command.command.ts +└── interactions/ + ├── my-button.button.ts + ├── my-menu.select.ts + └── my-modal.modal.ts +``` + +## API + +```typescript +interface InteractionHandler { + customId: string; // Unique identifier + requiresAdmin?: boolean; // Admin-only + check: (interaction) => interaction is T; // Type check + execute: (interaction, args[], config?) // Execution function + => Promise; +} +``` + +The `config` parameter is a `ConfigProvider` giving access to the module's configuration (see [Configuration](./configuration)). + +The `requiresAdmin` flag restricts the interaction to guild administrators. The check is enforced centrally by the system — no additional code needed. + +## Creating an interaction + +### Button + +```typescript +// src/modules/my-module/interactions/confirm.button.ts + +import { MessageFlags } from "discord.js"; +import { declareInteractionHandler } from "#lib/interaction.js"; + +export default declareInteractionHandler({ + customId: "confirm-action", + check: (interaction) => interaction.isButton(), + + async execute(interaction, [actionId, userId]) { + await interaction.reply({ + content: `Action ${actionId} confirmed for user ${userId}`, + flags: MessageFlags.Ephemeral, + }); + }, +}); +``` + +### Select menu + +```typescript +// src/modules/my-module/interactions/role-select.select.ts + +import { declareInteractionHandler } from "#lib/interaction.js"; + +export default declareInteractionHandler({ + customId: "role-select", + check: (interaction) => interaction.isStringSelectMenu(), + + async execute(interaction, [targetUserId]) { + const selectedRoles = interaction.values; + + await interaction.reply({ + content: `Roles ${selectedRoles.join(", ")} assigned to <@${targetUserId}>`, + ephemeral: true, + }); + }, +}); +``` + +### Modal + +```typescript +// src/modules/my-module/interactions/feedback.modal.ts + +import { declareInteractionHandler } from "#lib/interaction.js"; + +export default declareInteractionHandler({ + customId: "feedback-modal", + check: (interaction) => interaction.isModalSubmit(), + + async execute(interaction, [category]) { + const feedback = interaction.fields.getTextInputValue("feedback-input"); + + await interaction.reply({ + content: "Thank you for your feedback!", + ephemeral: true, + }); + }, +}); +``` + +## Custom ID with arguments + +The system supports passing arguments through the `customId` using `:` as separator: + +``` +customId:arg1:arg2:arg3 +``` + +### Usage in a command + +```typescript +import { ButtonBuilder, ButtonStyle } from "discord.js"; + +const button = new ButtonBuilder() + .setCustomId(`confirm-action:delete:${userId}`) + .setLabel("Confirm") + .setStyle(ButtonStyle.Danger); +``` + +Arguments are automatically extracted and passed to the handler as an array (`args`). + +## Registering in the module + +```typescript +// src/modules/my-module/my-module.module.ts +import confirmButton from "./interactions/confirm.button.js"; +import roleSelect from "./interactions/role-select.select.js"; + +export default defineModule({ + onLoad(_client, registry) { + registry.register(confirmButton); + registry.register(roleSelect); + }, +}); +``` + +## Automatic activation management + +The system handles interaction activation/deactivation automatically: + +- Interactions only work when the module is enabled on the guild +- No extra code needed to check module state +- Automatic error messages if the module is disabled +- Interactions marked `requiresAdmin: true` are auto-protected + +## Best practices + +### Argument validation + +```typescript +async execute(interaction, [userId, action]) { + if (!userId || !action) { + await interaction.reply({ + content: "Missing data. Please try again.", + ephemeral: true, + }); + return; + } +} +``` + +### Error handling + +```typescript +async execute(interaction, [targetId]) { + try { + await performRiskyOperation(targetId); + await interaction.reply({ content: "Success!", ephemeral: true }); + } catch (error) { + logger.error("Error:", error); + await interaction.reply({ + content: "An error occurred. Please try again.", + ephemeral: true, + }); + } +} +``` + +### Response types + +```typescript +// Instant action +await interaction.reply({ content: "Done!", ephemeral: true }); + +// Long running action +await interaction.deferReply({ ephemeral: true }); +await longOperation(); +await interaction.editReply({ content: "Finished!" }); + +// Update message (buttons) +await interaction.update({ content: "Updated", components: [] }); +``` + +## Next steps + +- [Configuration](./configuration) for managing module settings +- [Commands](./commands) for creating slash commands +- [Listeners](./listeners) for reacting to Discord events diff --git a/docs/en/guide/listeners.md b/docs/en/guide/listeners.md new file mode 100644 index 0000000..7aabe7f --- /dev/null +++ b/docs/en/guide/listeners.md @@ -0,0 +1,44 @@ +# Listeners + +Event listeners allow your module to react to Discord events. The module system automatically activates/deactivates listeners based on the module's installation state. + +> **Important**: For events that can occur in DMs (direct messages), you must manually check if the module is active, since the system cannot automatically detect module state outside of a guild. + +> **Discord Intents**: Make sure to add the required intents in `defineModule()` and in your Discord Developer Portal configuration. + +## Declaring a listener + +```typescript +// src/modules/my-module/listeners/message-create.listener.ts + +import { declareEventListener } from "#lib/listener.js"; + +export default declareEventListener({ + eventType: "messageCreate", + + async execute(message, config) { + // config is a ConfigProvider | undefined + // Your logic here + }, +}); +``` + +## Registering in the module + +```typescript +// src/modules/my-module/my-module.module.ts +import messageListener from "./listeners/message-create.listener.js"; + +export default defineModule({ + onLoad(_client, registry) { + registry.register(messageListener); + }, +}); +``` + +The system automatically enables or disables the listener based on whether the module is installed on the relevant guild. + +## Next steps + +- [Configuration](./configuration) for managing module settings +- [Database](./database) for persistent data diff --git a/docs/en/guide/services.md b/docs/en/guide/services.md new file mode 100644 index 0000000..3698cf8 --- /dev/null +++ b/docs/en/guide/services.md @@ -0,0 +1,53 @@ +# Services + +Services allow you to encapsulate business logic and reuse it across your module. + +## Creating a service + +```typescript +// src/modules/my-module/services/user.service.ts + +import { declareService, type Service } from "#lib/service.js"; +import prisma from "#lib/database.js"; + +class UserService implements Service { + async createUser(userId: string, username: string) { + return await prisma.user.create({ + data: { userId, username }, + }); + } + + async getUser(userId: string) { + return await prisma.user.findUnique({ + where: { userId }, + }); + } +} + +export default declareService(new UserService()); +``` + +## Service interface + +`declareService` accepts any class instance. The `Service` interface is currently empty, allowing great flexibility in service structure. + +## Usage + +Services can be imported and used in commands, listeners, or other services: + +```typescript +// In a command +import userService from "../services/user.service.js"; + +async execute(interaction) { + const user = await userService.getUser(interaction.user.id); + // ... +} +``` + +## Best practices + +- Use services to encapsulate complex business logic +- Keep services focused on a single responsibility +- Use services for database interactions +- Always export an instance declared with `declareService` diff --git a/docs/en/index.md b/docs/en/index.md new file mode 100644 index 0000000..bad17a1 --- /dev/null +++ b/docs/en/index.md @@ -0,0 +1,29 @@ +--- +layout: home + +hero: + name: OmniBot + text: Modular Discord Bot + tagline: Documentation for creating and extending the bot's functionality. + actions: + - theme: brand + text: Get Started + link: /en/guide/getting-started + - theme: alt + text: Create a Module + link: /en/guide/creating-a-module + +features: + - icon: 🧩 + title: Self-contained modules + details: Each feature is an independent module, installable per guild. + - icon: ⚡ + title: Slash commands + details: Create typed slash commands with autocomplete support. + - icon: 🔔 + title: Event listeners + details: React to Discord events with per-module auto-activation. + - icon: 🎛️ + title: Typed configuration + details: Declare a config schema and get an interactive editing UI. +--- From 72bad69584905208932dd64cb7d7bd27b3d9c560 Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:26:44 +0200 Subject: [PATCH 05/14] ci: add GitHub Actions workflow to build and deploy docs - Use jdx/mise-action v2 for Node/pnpm from .mise.toml - pnpm install --frozen-lockfile, then build docs - Deploy to GitHub Pages via actions/upload-pages-artifact and actions/deploy-pages - Trigger: push to master touching docs/** or CI config --- .github/workflows/docs.yml | 46 +++++++++ docs/commands.md | 80 --------------- docs/interactions.md | 201 ------------------------------------- docs/listeners.md | 53 ---------- docs/modules.md | 140 -------------------------- docs/prisma.md | 181 --------------------------------- docs/services.md | 69 ------------- 7 files changed, 46 insertions(+), 724 deletions(-) create mode 100644 .github/workflows/docs.yml delete mode 100644 docs/commands.md delete mode 100644 docs/interactions.md delete mode 100644 docs/listeners.md delete mode 100644 docs/modules.md delete mode 100644 docs/prisma.md delete mode 100644 docs/services.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..ea0773f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,46 @@ +name: Deploy docs to GitHub Pages + +on: + push: + branches: [master] + paths: + - "docs/**" + - ".github/workflows/docs.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: jdx/mise-action@v2 + + - run: pnpm install --frozen-lockfile + + - run: pnpm --filter omnibot-docs build + env: + DOCS_BASE: /OmniBot/ + + - uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/deploy-pages@v4 + id: deployment diff --git a/docs/commands.md b/docs/commands.md deleted file mode 100644 index 77b0fd5..0000000 --- a/docs/commands.md +++ /dev/null @@ -1,80 +0,0 @@ -# Commandes Discord - -Ce guide explique comment créer des commandes Discord dans vos modules. -Ces commandes sont des interactions slash qui permettent aux utilisateurs d'interagir avec votre bot. Elles ne seront -disponibles que si le module est activé, et sur le serveur. - -## Structure des Commandes - -Les commandes Discord sont des interactions slash ("/") que les utilisateurs peuvent exécuter. Chaque commande doit être -définie dans un fichier séparé dans le dossier `commands/` de votre module. - -### Structure de fichier - -``` -src/modules/mon-module/ -├── module.ts -└── commands/ - └── ma-commande.command.ts -``` - -## Création d'une Commande - -```typescript -// src/modules/mon-module/commands/test.command.ts -import { SlashCommandBuilder } from "discord.js"; -import { declareCommand } from "../../../lib/command.js"; - -export default declareCommand({ - data: new SlashCommandBuilder() - .setName("test") - .setDescription("Commande de test"), - - async execute(interaction) { - await interaction.reply("Test !"); - }, -}); -``` - -## Interface Command - -La fonction `declareCommand` accepte un objet qui implémente l'interface `Command` : - -- `data` : Configuration de la commande (SlashCommandBuilder) -- `execute` : Fonction d'exécution (obligatoire) -- `complete` : Fonction d'autocomplétion (optionnelle) - -## Enregistrement dans le Module - -```typescript -// src/modules/mon-module/mon-module.module.ts -import messageListener from "./commands/test.command.js"; - -export default defineModule({ - onLoad(client, registry) { - // Le système gère automatiquement l'enregistrement et la désactivation des commandes - registry.register(testCommand); - }, -}); -``` - -## Enregistrement & propagation - -L'enregistrement des commandes auprès de Discord dépend du type de commande et -du mode d'exécution : - -| Commandes | Production | Développement (`NODE_ENV=development`) | -| -------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | -| **core** (`/config`, `/modules`) | globales (propagation jusqu'à ~1 h) | enregistrées sur `DEV_GUILD_ID` → **instantané** | -| **module** | par serveur, (ré)installées au changement de `version` du module | re-synchronisées **à chaque démarrage** sur `DEV_GUILD_ID` pour les modules activés, sans bump de version | - -En production, le gate par version évite de re-pousser les commandes d'un module -sur toutes les guildes à chaque démarrage. En développement ce gate est une -friction (une seule guilde, itérations rapides) : `loadDevGuildCommands` -enregistre, en **un seul PUT** sur la dev guild, le core + les commandes de tous -les modules activés. Le PUT unique est nécessaire car il écrase l'ensemble des -commandes de la guilde — mélanger un PUT (core) et des POST (modules) sur le même -scope ferait disparaître les commandes POST. - -> `DEV_GUILD_ID` est **requis** en mode dev (validé au démarrage). Voir -> `.env.example`. diff --git a/docs/interactions.md b/docs/interactions.md deleted file mode 100644 index 45a0356..0000000 --- a/docs/interactions.md +++ /dev/null @@ -1,201 +0,0 @@ -# Guide des Interactions Discord - -Les interactions Discord permettent à votre module de réagir aux interactions des utilisateurs avec des composants UI comme les boutons, menus déroulants et modales. Ce système complète les commandes slash et les listeners d'événements. - -## Types d'Interactions Supportées - -AsyncMod supporte deux types d'interactions : - -- **Message Component Interactions** : Boutons, menus déroulants, etc. -- **Modal Submit Interactions** : Soumissions de formulaires modaux - -## Structure des Interactions - -### Structure de fichier - -``` -src/modules/mon-module/ -├── module.ts -├── commands/ -│ └── ma-commande.command.ts -└── interactions/ - ├── mon-bouton.button.ts - ├── mon-menu.select.ts - └── ma-modale.modal.ts -``` - -## API des Interactions - -### Interface InteractionHandler - -```typescript -export interface InteractionHandler { - customId: string; // Identifiant unique - check: (interaction: CompatibleInteraction) => interaction is T; // Vérification du type - execute: (interaction: T, args: string[]) => Promise; // Fonction d'exécution -} -``` - -## Création d'une Interaction - -### Exemple : Bouton - -```typescript -// src/modules/mon-module/interactions/confirm.button.ts -import { MessageFlags } from "discord.js"; -import { declareInteractionHandler } from "../../../lib/interaction.js"; - -export default declareInteractionHandler({ - customId: "confirm-action", - check: (interaction) => interaction.isButton(), - - async execute(interaction, [actionId, userId]) { - await interaction.reply({ - content: `Action ${actionId} confirmée pour l'utilisateur ${userId}`, - flags: MessageFlags.Ephemeral, - }); - }, -}); -``` - -### Exemple : Menu Déroulant - -```typescript -// src/modules/mon-module/interactions/role-select.select.ts -import { declareInteractionHandler } from "../../../lib/interaction.js"; - -export default declareInteractionHandler({ - customId: "role-select", - check: (interaction) => interaction.isStringSelectMenu(), - - async execute(interaction, [targetUserId]) { - const selectedRoles = interaction.values; - - await interaction.reply({ - content: `Rôles ${selectedRoles.join(", ")} attribués à <@${targetUserId}>`, - ephemeral: true, - }); - }, -}); -``` - -### Exemple : Modal - -```typescript -// src/modules/mon-module/interactions/feedback.modal.ts -import { declareInteractionHandler } from "../../../lib/interaction.js"; - -export default declareInteractionHandler({ - customId: "feedback-modal", - check: (interaction) => interaction.isModalSubmit(), - - async execute(interaction, [category]) { - const feedback = interaction.fields.getTextInputValue("feedback-input"); - - // Traitement du feedback - console.log(`Feedback reçu (${category}): ${feedback}`); - - await interaction.reply({ - content: "Merci pour votre retour !", - ephemeral: true, - }); - }, -}); -``` - -## Système de Custom ID avec Arguments - -Le système AsyncMod permet de passer des arguments via le `customId` : - -``` -customId:arg1:arg2:arg3 -``` - -### Utilisation dans une commande - -```typescript -// Dans une commande qui crée un bouton -const button = new ButtonBuilder() - .setCustomId(`confirm-action:delete:${userId}`) - .setLabel("Confirmer") - .setStyle(ButtonStyle.Danger); -``` - -## Enregistrement dans le Module - -```typescript -// src/modules/mon-module/mon-module.module.ts -import confirmButton from "./interactions/confirm.button.js"; -import roleSelect from "./interactions/role-select.select.js -"; - -export default defineModule({ - onLoad(client, registry) { - registry.register(confirmButton); - registry.register(roleSelect); - }, -}); -``` - -## Gestion Automatique de l'Activation - -Le système AsyncMod gère automatiquement l'activation/désactivation des interactions : - -- ✅ Les interactions ne fonctionnent que si le module est activé sur le serveur -- ✅ Pas de code supplémentaire nécessaire pour vérifier l'état -- ✅ Messages d'erreur automatiques si le module est désactivé - -## Bonnes Pratiques - -### 1. Validation des Arguments - -```typescript -async execute(interaction, [userId, action]) { - if (!userId || !action) { - await interaction.reply({ - content: "Données manquantes. Veuillez réessayer.", - ephemeral: true, - }); - return; - } - // Logique principale -} -``` - -### 2. Gestion des Erreurs - -```typescript -async execute(interaction, [targetId]) { - try { - await performRiskyOperation(targetId); - await interaction.reply({ content: "Opération réussie !", ephemeral: true }); - } catch (error) { - console.error("Erreur:", error); - await interaction.reply({ - content: "Une erreur s'est produite. Veuillez réessayer.", - ephemeral: true, - }); - } -} -``` - -### 3. Types de Réponses - -```typescript -// Action instantanée -await interaction.reply({ content: "Fait !", ephemeral: true }); - -// Action longue -await interaction.deferReply({ ephemeral: true }); -await longOperation(); -await interaction.editReply({ content: "Terminé !" }); - -// Mise à jour du message (boutons) -await interaction.update({ content: "Mis à jour", components: [] }); -``` - -## Prochaines Étapes - -- [Configuration des Modules](./modules.md) pour gérer les paramètres -- [Commandes Discord](./commands.md) pour créer des commandes slash -- [Guide des Listeners](./listeners.md) pour réagir aux événements diff --git a/docs/listeners.md b/docs/listeners.md deleted file mode 100644 index 2cbdcaf..0000000 --- a/docs/listeners.md +++ /dev/null @@ -1,53 +0,0 @@ -# Guide des Listeners - -Les listeners (écouteurs d'événements) dans AsyncMod permettent à votre module de réagir aux événements Discord. Le -système de modules gère automatiquement l'activation/désactivation des listeners selon l'état du module. - -> ⚠️ **Important**: Pour les événements pouvant se produire en MP (messages privés), vous devez gérer manuellement la -> vérification d'activation du module car le système ne peut pas détecter automatiquement si le module est actif en -> dehors d'un serveur. - -> 📋 **Intents Discord**: Assurez-vous d'ajouter les bons intents dans votre configuration Discord pour recevoir les -> événements souhaités. - -## API des Listeners - -### Déclaration d'un Listener - -```typescript -import { declareEventListener } from "../../../lib/listener.js"; - -export default declareEventListener({ - eventType: "messageCreate", // Type d'événement Discord - - async execute(...args) { - // Votre logique ici - // Les arguments dépendent du type d'événement - }, -}); -``` - -### Enregistrement dans le Module - -```typescript -// src/modules/mon-module/mon-module.module.ts -import messageListener from "./listeners/message-create.listener.js"; - -export default defineModule({ - onLoad(client, registry) { - // Le système gère automatiquement l'activation/désactivation - registry.register(messageListener); - }, -}); -``` - -## Configuration des Intents Discord - -Les intents sont requis pour recevoir certains événements. -Pour plus d'informations sur quels intents sont nécessaires pour chaque événement, consultez -la [documentation Discord](https://discord.com/developers/docs/events/gateway#list-of-intents). - -## Prochaines Étapes - -- [Configuration des Modules](./modules.md) pour gérer les paramètres -- [Gestion de la BDD](./prisma.md) pour les données persistantes diff --git a/docs/modules.md b/docs/modules.md deleted file mode 100644 index 2f8b596..0000000 --- a/docs/modules.md +++ /dev/null @@ -1,140 +0,0 @@ -# Guide des Modules - -Un module dans AsyncMod est une unité fonctionnelle autonome qui peut être installée et désinstallée par serveur -Discord. Chaque module peut contenir des commandes, des listeners d'événements et ses propres données. - -## Structure d'un Module - -``` -src/modules/mon-module/ -├── mon-module.module.ts # Définition du module principal -├── commands/ # Commandes du module -│ └── ma-commande.command.ts -├── listeners/ # Listeners d'événements -│ └── mon-listener.listener.ts -└── models/ # Modèles de données (optionnel) - └── mon-modele.prisma -``` - -## Création d'un Module - -### 1. Définition du Module Principal - -Créez le fichier principal de votre module : - -```typescript -// src/modules/mon-module/mon-module.module.ts - -export default defineModule({ - id: "mon-module", - name: "Mon Module", - description: "Description de mon module personnalisé.", - version: "1.0.0", - author: "Votre Nom", // Optionnel - - // Intents Discord requis par le module - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - ], - - // Appelé au démarrage du bot - onLoad(client, registry) { - // Enregistrer les commandes - registry.register(maCommande); - - // Enregistrer les listeners - registry.register(monListener); - - // Enregistrer les interactions - registry.register(monInteraction); - - logger.info("Mon module chargé avec succès"); - }, - - // Appelé quand le module est installé sur un serveur - onInstall(client, guild, registry) { - logger.info(`Mon module installé sur ${guild.name}`); - - // Exemples de logique d'installation : - // - Créer des rôles - // - Configurer des channels - // - Initialiser des données - }, - - // Appelé quand le module est désinstallé d'un serveur - onUninstall(client, guild, registry) { - logger.info(`Mon module désinstallé de ${guild.name}`); - - // Exemple de logique de nettoyage : - // - Supprimer des données - // - Nettoyer des configurations - }, -}); -``` - -### 2. Interface ModuleDeclaration - -Voici les propriétés disponibles pour définir un module : - -```typescript -interface ModuleDeclaration { - id: string; // Identifiant unique (requis) - name: string; // Nom d'affichage (requis) - description: string; // Description (requis) - version: string; // Version semver (requis) - author?: string; // Auteur (optionnel) - intents?: GatewayIntentBits[]; // Intents Discord (optionnel) - - // Hooks du cycle de vie - onLoad: (client, registry) => void; - onInstall: (client, guild, registry) => void; - onUninstall: (client, guild, registry) => void; -} -``` - -## Bonnes Pratiques - -### Naming Convention - -- **ID du module** : kebab-case (`mon-super-module`) -- **Nom du fichier** : `{id}.module.ts` -- **Dossier** : même nom que l'ID du module - -### Gestion des Intents - -Ne déclarez uniquement les intents nécessaires à votre module. - -### Gestion des Erreurs - -Toujours gérer les erreurs dans les hooks : - -```typescript -onInstall(client, guild, registry); -{ - try { - // Logique d'installation - } catch (error) { - logger.error(`Erreur lors de l'installation du module : ${error.message}`); - } -} -``` - -### Organisation des Fichiers - -- Gardez le fichier principal du module léger -- Séparez la logique complexe dans des services -- Utilisez des sous-dossiers pour organiser commandes et listeners - -## Découverte automatique - -Les modules sont chargés automatiquement depuis `src/modules/` au démarrage — aucun enregistrement manuel n'est nécessaire en dehors du dossier du module. - -## Prochaines Étapes - -Une fois votre module créé, consultez : - -- [Guide des Commandes](./commands.md) pour ajouter des commandes -- [Guide des Listeners](./listeners.md) pour écouter des événements -- [Guide des Interactions](./interactions.md) pour définir des interactions (boutons, modal, etc.) diff --git a/docs/prisma.md b/docs/prisma.md deleted file mode 100644 index 0bf773c..0000000 --- a/docs/prisma.md +++ /dev/null @@ -1,181 +0,0 @@ -# Configuration Prisma - AsyncMod - -## Vue d'ensemble - -Ce projet utilise Prisma comme ORM avec une architecture modulaire personnalisée qui permet de distribuer les modèles de -base de données à travers différents modules tout en maintenant un schéma consolidé. - -## Architecture - -### Structure des fichiers - -``` -src/ -├── prisma/ -│ ├── header.prisma # Configuration du générateur et datasource -│ └── schema.prisma # Schéma consolidé (généré automatiquement) -├── core/ -│ └── models/ -│ └── modules.prisma # Modèles du système de modules -└── modules/ - └── [module-name]/ - └── models/ - └── *.prisma # Modèles spécifiques au module -``` - -### Configuration - -#### dbinfo.prisma - -Le fichier `dbinfo.prisma` contient la configuration de base qui sera utilisée pour tous les schémas consolidés : - -```prisma -generator client { - provider = "prisma-client-js" - output = "../src/generated/prisma" -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} -``` - -**Avantages de cette approche :** - -- Configuration centralisée et modifiable -- Possibilité de changer facilement la base de données ou les options du générateur -- Séparation claire entre configuration et modèles - -## Système de consolidation des modèles - -### Principe - -Au lieu d'avoir tous les modèles dans un seul fichier `schema.prisma`, ce projet permet de distribuer les modèles dans -différents fichiers `.prisma` à travers les modules. Un script de consolidation (`scripts/consolidate-schema.ts`) -rassemble automatiquement tous ces modèles avec le header dans le schéma principal. - -### Script de consolidation - -Le script `consolidate-schema.ts` : - -1. **Recherche récursive** : Parcourt tous les dossiers dans `src/` pour trouver les fichiers `.prisma` (sauf - dans le dossier `src/prisma/`) -2. **Consolidation** : Combine le header et tous les modèles trouvés dans un seul `schema.prisma` -3. **Organisation** : Ajoute des commentaires pour identifier la source de chaque modèle - -## Scripts NPM - -Le projet fournit plusieurs scripts pour faciliter le travail avec Prisma : - -```json -{ - "prisma:consolidate": "tsx scripts/consolidate-schema.ts", - "prisma:generate": "pnpm prisma:consolidate && prisma generate", - "prisma:migrate": "pnpm prisma:consolidate && prisma migrate dev", - "prisma:studio": "pnpm prisma:consolidate && prisma studio" -} -``` - -### Description des scripts - -- **`prisma:consolidate`** : Exécute uniquement la consolidation des modèles -- **`prisma:generate`** : Consolide puis génère le client Prisma -- **`prisma:migrate`** : Consolide puis crée/applique les migrations -- **`prisma:studio`** : Consolide puis lance Prisma Studio - -## Workflow de développement - -### 1. Ajouter un nouveau modèle - -1. Créer un fichier `.prisma` dans le dossier `models/` de votre module : - - ``` - src/modules/mon-module/models/mon-modele.prisma - ``` - -2. Définir votre modèle : - ```prisma - model MonModele { - id String @id @default(cuid()) - nom String - // ... autres champs - } - ``` - -### 2. Générer le client - -```bash -pnpm prisma:generate -``` - -Cette commande : - -1. Consolide tous les modèles -2. Génère le client TypeScript typé - -### 3. Créer une migration - -```bash -pnpm prisma:migrate -``` - -Cette commande : - -1. Consolide tous les modèles -2. Crée une nouvelle migration -3. L'applique à la base de données - -## Bonnes pratiques - -### Organisation des modèles - -- **Modèles du core** : `src/core/models/` -- **Modèles spécifiques aux modules** : `src/modules/[module-name]/models/` -- **Réduire le nombre de modèles par fichier** : Facilite la maintenance et la lecture - -### Nommage - -- **Fichiers** : `nom-descriptif.prisma` -- **Modèles** : PascalCase (ex: `ModuleActivation`) -- **Champs** : camelCase (ex: `moduleId`) - -## Dépannage - -### Erreur de consolidation - -Si le script de consolidation échoue : - -1. Vérifiez la syntaxe Prisma de tous vos fichiers `.prisma` -2. Assurez-vous qu'il n'y a pas de conflits de noms de modèles -3. Vérifiez les permissions de fichiers - -### Erreur de génération - -Si `prisma generate` échoue après consolidation : - -1. Vérifiez le fichier `schema.prisma` généré -2. Recherchez les erreurs de syntaxe ou de relations -3. Assurez-vous que toutes les relations sont valides - -### Problèmes de migration - -En cas de problème avec les migrations : - -1. Vérifiez que votre base de données est accessible -2. Assurez-vous que `DATABASE_URL` est correctement configurée -3. Consultez les logs de migration pour plus de détails - -## Variables d'environnement - -Assurez-vous d'avoir configuré dans votre fichier `.env` : - -```env -DATABASE_URL="postgresql://username:password@localhost:5432/database_name" -``` - -## Ressources utiles - -- [Documentation Prisma](https://www.prisma.io/docs/) -- [Prisma Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference) -- [Prisma Client API](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference) diff --git a/docs/services.md b/docs/services.md deleted file mode 100644 index fb839f4..0000000 --- a/docs/services.md +++ /dev/null @@ -1,69 +0,0 @@ -# Services - -Ce guide explique comment créer des services dans vos modules pour organiser la logique métier. - -## Structure des Services - -Les services permettent d'encapsuler la logique métier et de la réutiliser à travers votre module. Chaque service doit -être défini dans un fichier séparé dans le dossier `services/` de votre module. - -### Structure de fichier - -``` -src/modules/mon-module/ -├── mon-module.module.ts -└── services/ - └── mon-service.service.ts -``` - -## Création d'un Service - -```typescript -// src/modules/mon-module/services/user.service.ts -import { declareService, type Service } from "../../../lib/service.js"; -import prisma from "../../../lib/database.js"; - -class UserService implements Service { - async createUser(userId: string, username: string) { - return await prisma.user.create({ - data: { userId, username }, - }); - } - - async getUser(userId: string) { - return await prisma.user.findUnique({ - where: { userId }, - }); - } -} - -export default declareService(new UserService()); -``` - -## Interface Service - -La fonction `declareService` accepte une instance de classe qui implémente l'interface `Service`. L'interface est -actuellement vide, permettant une grande flexibilité dans la structure de vos services. - -## Utilisation - -Les services peuvent être importés et utilisés dans vos commandes, listeners ou autres services : - -```typescript -// Dans une commande -import userService from "../services/user.service.js"; - -async; -execute(interaction); -{ - const user = await userService.getUser(interaction.user.id); - // ... -} -``` - -## Bonnes Pratiques - -- Utilisez les services pour encapsuler la logique métier -- Gardez les services focalisés sur une responsabilité spécifique -- Utilisez les services pour les interactions avec la base de données -- Exportez toujours une instance déclarée avec `declareService` From a4cf50867aec67ba0f8c20750c1e72bcdf8d05ea Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:28:51 +0200 Subject: [PATCH 06/14] ci: allow testing workflow on vitepress-docs branch (deploy only on master) --- .github/workflows/docs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ea0773f..0e647bb 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Deploy docs to GitHub Pages on: push: - branches: [master] + branches: [master, vitepress-docs] paths: - "docs/**" - ".github/workflows/docs.yml" @@ -37,6 +37,7 @@ jobs: deploy: needs: build + if: github.ref == 'refs/heads/master' runs-on: ubuntu-latest environment: name: github-pages From ff0147905eca910850e11a63fa6035affe60a198 Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:29:31 +0200 Subject: [PATCH 07/14] ci: deploy on all branches for testing --- .github/workflows/docs.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0e647bb..2c8624a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -37,11 +37,7 @@ jobs: deploy: needs: build - if: github.ref == 'refs/heads/master' runs-on: ubuntu-latest - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} steps: - uses: actions/deploy-pages@v4 id: deployment From a57a66572483c2cd1f0297dfeb596c0f40088675 Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:34:19 +0200 Subject: [PATCH 08/14] docs: add root landing page with language selection - Add index.md as a VitePress landing page - Restructure locales: fr/ and en/ instead of root=fr - Add Accueil/Home nav links to both locales --- docs/.vitepress/config.ts | 8 ++++---- docs/index.md | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 docs/index.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 09b6e9b..22c6fc8 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -31,16 +31,16 @@ export default defineConfig({ }, locales: { - root: { + fr: { label: "Français", lang: "fr", - link: "/", + link: "/fr/", title: "OmniBot", description: "Documentation du bot Discord modulaire OmniBot", themeConfig: { nav: [ + { text: "Accueil", link: "/" }, { text: "Guide", link: "/fr/guide/getting-started" }, - { text: "Modules", link: "/fr/guide/creating-a-module" }, ], sidebar: { "/fr/guide/": [ @@ -85,7 +85,7 @@ export default defineConfig({ themeConfig: { nav: [ { text: "Guide", link: "/en/guide/getting-started" }, - { text: "Modules", link: "/en/guide/creating-a-module" }, + { text: "Home", link: "/" }, ], sidebar: { "/en/guide/": [ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..991603a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,40 @@ +--- +layout: home + +hero: + name: OmniBot + text: Bot Discord modulaire + tagline: Un bot Discord modulaire, extensible et configurable. + image: + src: /logo.svg + alt: OmniBot + actions: + - theme: brand + text: Documentation + link: /fr/guide/getting-started + - theme: alt + text: English docs + link: /en/guide/getting-started + +features: + - icon: 🧩 + title: Modules autonomes + details: Chaque fonctionnalité est un module indépendant, installable par serveur. + - icon: ⚡ + title: Commandes slash + details: Créez des commandes slash typées avec autocomplétion. + - icon: 🔔 + title: Écouteurs d'événements + details: Réagissez aux événements Discord avec activation automatique. + - icon: 🎛️ + title: Configuration typée + details: Déclarez un schéma de configuration et obtenez une UI interactive. + - icon: 🇫🇷 + title: Documentation française + details: Documentation complète en français pour créer des modules. + link: /fr/guide/getting-started + - icon: 🇬🇧 + title: English documentation + details: Full English documentation for module development. + link: /en/guide/getting-started +--- From eae5d2558fc48fdd89b9b222c64494f511db8597 Mon Sep 17 00:00:00 2001 From: RedsTom Date: Sun, 14 Jun 2026 03:35:42 +0200 Subject: [PATCH 09/14] ci: restrict docs deployment to master branch only --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2c8624a..3dd3552 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Deploy docs to GitHub Pages on: push: - branches: [master, vitepress-docs] + branches: [master] paths: - "docs/**" - ".github/workflows/docs.yml" From 614a7905d667e99732ba43bf49b41241cd327894 Mon Sep 17 00:00:00 2001 From: Antoine James Tournepiche Date: Sun, 14 Jun 2026 15:26:27 +0200 Subject: [PATCH 10/14] refactor(docs): relocate VitePress site to docs/site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move the VitePress site under `docs/site/` and lift the internal notes (`functional.md`, `specs/`, `review/`) out of `_internal/` back to `docs/`. - Point `pnpm-workspace.yaml` at `docs/site` and regenerate the root `pnpm-lock.yaml` as the single source of truth. - Remove the nested `docs/pnpm-lock.yaml` (ignored inside a workspace and a source of divergence). - Fix `pnpm --filter docs` → `--filter omnibot-docs` in README/AGENTS, repoint the AGENTS doc table, and trim now-dead `srcExclude` entries. Co-Authored-By: Claude Opus 4.8 --- AGENTS.md | 26 +- docs/{_internal => }/functional.md | 11 +- docs/pnpm-lock.yaml | 1620 ----------------- .../review/config-completion-findings.md | 3 + .../review/dev-guild-commands-findings.md | 0 docs/{ => site}/.gitignore | 0 docs/{ => site}/.vitepress/config.ts | 14 +- docs/{ => site}/README.md | 11 +- docs/{ => site}/en/guide/configuration.md | 0 docs/{ => site}/en/guide/creating-a-module.md | 0 docs/{ => site}/en/guide/database.md | 0 docs/{ => site}/en/guide/getting-started.md | 0 docs/{ => site}/en/guide/listeners.md | 0 docs/{ => site}/en/guide/services.md | 0 docs/{ => site}/en/index.md | 0 docs/{ => site}/fr/guide/configuration.md | 0 docs/{ => site}/fr/guide/creating-a-module.md | 0 docs/{ => site}/fr/guide/database.md | 0 docs/{ => site}/fr/guide/getting-started.md | 0 docs/{ => site}/fr/guide/listeners.md | 0 docs/{ => site}/fr/guide/services.md | 0 docs/{ => site}/fr/index.md | 0 docs/{ => site}/package.json | 0 docs/{_internal => }/specs/autopin.md | 0 docs/{_internal => }/specs/module-config.md | 0 .../specs/thread-creator-queue.md | 0 pnpm-lock.yaml | 210 +-- pnpm-workspace.yaml | 2 +- 28 files changed, 135 insertions(+), 1762 deletions(-) rename docs/{_internal => }/functional.md (88%) delete mode 100644 docs/pnpm-lock.yaml rename docs/{_internal => }/review/config-completion-findings.md (99%) rename docs/{_internal => }/review/dev-guild-commands-findings.md (100%) rename docs/{ => site}/.gitignore (100%) rename docs/{ => site}/.vitepress/config.ts (93%) rename docs/{ => site}/README.md (50%) rename docs/{ => site}/en/guide/configuration.md (100%) rename docs/{ => site}/en/guide/creating-a-module.md (100%) rename docs/{ => site}/en/guide/database.md (100%) rename docs/{ => site}/en/guide/getting-started.md (100%) rename docs/{ => site}/en/guide/listeners.md (100%) rename docs/{ => site}/en/guide/services.md (100%) rename docs/{ => site}/en/index.md (100%) rename docs/{ => site}/fr/guide/configuration.md (100%) rename docs/{ => site}/fr/guide/creating-a-module.md (100%) rename docs/{ => site}/fr/guide/database.md (100%) rename docs/{ => site}/fr/guide/getting-started.md (100%) rename docs/{ => site}/fr/guide/listeners.md (100%) rename docs/{ => site}/fr/guide/services.md (100%) rename docs/{ => site}/fr/index.md (100%) rename docs/{ => site}/package.json (100%) rename docs/{_internal => }/specs/autopin.md (100%) rename docs/{_internal => }/specs/module-config.md (100%) rename docs/{_internal => }/specs/thread-creator-queue.md (100%) diff --git a/AGENTS.md b/AGENTS.md index 502eefd..9d4d740 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,19 +34,19 @@ Daemons are defined in `pitchfork.toml` (`bot` depends on `db`). Requires Docker OmniBot is a modular Discord bot. The core loads modules dynamically — **no registration needed outside the module directory**, modules are auto-discovered at startup. Each module is a self-contained plugin installed/uninstalled per guild. -See [`docs/`](docs/README.md) for the full developer guide: - -| Topic | Doc | -| -------------------------- | -------------------------------------------- | -| Creating a module | [docs/modules.md](docs/modules.md) | -| Slash commands | [docs/commands.md](docs/commands.md) | -| Event listeners | [docs/listeners.md](docs/listeners.md) | -| Buttons / modals / selects | [docs/interactions.md](docs/interactions.md) | -| Services | [docs/services.md](docs/services.md) | -| Prisma multi-file schema | [docs/prisma.md](docs/prisma.md) | -| Functional behavior | [docs/functional.md](docs/functional.md) | - -The docs are also published as a VitePress site at [`docs/`](docs/) — run `pnpm --filter docs dev` to preview. +See [`docs/site/`](docs/site/README.md) for the full developer guide: + +| Topic | Doc | +| -------------------------- | ---------------------------------------------------------------------------------- | +| Creating a module | [docs/site/en/guide/creating-a-module.md](docs/site/en/guide/creating-a-module.md) | +| Slash commands | [docs/site/en/guide/commands.md](docs/site/en/guide/commands.md) | +| Event listeners | [docs/site/en/guide/listeners.md](docs/site/en/guide/listeners.md) | +| Buttons / modals / selects | [docs/site/en/guide/interactions.md](docs/site/en/guide/interactions.md) | +| Services | [docs/site/en/guide/services.md](docs/site/en/guide/services.md) | +| Prisma / database | [docs/site/en/guide/database.md](docs/site/en/guide/database.md) | +| Functional behavior | [docs/functional.md](docs/functional.md) | + +The docs are also published as a VitePress site (sources in `docs/site/`) — run `pnpm --filter omnibot-docs dev` to preview. ## Key rules diff --git a/docs/_internal/functional.md b/docs/functional.md similarity index 88% rename from docs/_internal/functional.md rename to docs/functional.md index 78c3e01..be1f087 100644 --- a/docs/_internal/functional.md +++ b/docs/functional.md @@ -28,11 +28,12 @@ Dès qu'un message est posté dans le salon configuré : 2. Si un message de bienvenue est configuré, le bot le poste dans le fil **Variables disponibles dans le template de nom :** -| Variable | Valeur | -|---|---| -| `{messageAuthor}` | Nom d'affichage ou pseudo de l'auteur | -| `{messageContent}` | 50 premiers caractères du message | -| `{timestamp}` | Heure au format `JJ/MM HH:MM` (locale française) | + +| Variable | Valeur | +| ------------------ | ------------------------------------------------ | +| `{messageAuthor}` | Nom d'affichage ou pseudo de l'auteur | +| `{messageContent}` | 50 premiers caractères du message | +| `{timestamp}` | Heure au format `JJ/MM HH:MM` (locale française) | **Template par défaut :** `Discussion - {messageAuthor}` **Message de bienvenue par défaut :** `💬 Utilisez ce fil pour discuter de ce sujet !` diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml deleted file mode 100644 index 81e5cc9..0000000 --- a/docs/pnpm-lock.yaml +++ /dev/null @@ -1,1620 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - vitepress: - specifier: ^1.6.4 - version: 1.6.4(@algolia/client-search@5.54.0)(postcss@8.5.15)(search-insights@2.17.3) - -packages: - - '@algolia/abtesting@1.20.0': - resolution: {integrity: sha512-5CqkS592H3+24b6H6CQ2RVpphdmAuIElZzv0Hngqo/ZEZpUZJ+KGLcueBhx33fv2wYBXyuuvskG5aQ7Ti+lR0g==} - engines: {node: '>= 14.0.0'} - - '@algolia/autocomplete-core@1.17.7': - resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==} - - '@algolia/autocomplete-plugin-algolia-insights@1.17.7': - resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==} - peerDependencies: - search-insights: '>= 1 < 3' - - '@algolia/autocomplete-preset-algolia@1.17.7': - resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==} - peerDependencies: - '@algolia/client-search': '>= 4.9.1 < 6' - algoliasearch: '>= 4.9.1 < 6' - - '@algolia/autocomplete-shared@1.17.7': - resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==} - peerDependencies: - '@algolia/client-search': '>= 4.9.1 < 6' - algoliasearch: '>= 4.9.1 < 6' - - '@algolia/client-abtesting@5.54.0': - resolution: {integrity: sha512-IXnH1x3DBsPQA4/FRO0Pvkfy79tKy5Qr+ugAV9jdcGkpzHc476D0WV1MFJ+pZxtbts0xh2JqzUVmYEqA6LkOpA==} - engines: {node: '>= 14.0.0'} - - '@algolia/client-analytics@5.54.0': - resolution: {integrity: sha512-pBpRqm1wpE0GnGy2rNLk9rjDn0Le4iywNRtnAWblLeqfjxpWKg8lWnk7nmSoTShFO31sz2jatXXzxK2lz8ipbA==} - engines: {node: '>= 14.0.0'} - - '@algolia/client-common@5.54.0': - resolution: {integrity: sha512-WbuwRUlFvSOsuxqTDjSSmgusuF5KFt+oFPzobvPDvodra6EWnVwUXjz0elkNSsnsIlZGtcXlX3LhxkO7rF90jw==} - engines: {node: '>= 14.0.0'} - - '@algolia/client-insights@5.54.0': - resolution: {integrity: sha512-/HNLVi3kPI+JhO59WbglLjPM2c4uECU+x4gk1iADseKtE5eYqJ/RJ+FIwM8xzPFKhFJaw+8hVq4lkd0nn8HDDg==} - engines: {node: '>= 14.0.0'} - - '@algolia/client-personalization@5.54.0': - resolution: {integrity: sha512-6TolyyDRumIKeLGBGSFAZsSIJ8hrm6NFCGR1jO7pQTiOtSWgAIxcFE5/JRpZ3g+unG4OkNOFy+I0dUEquIDbig==} - engines: {node: '>= 14.0.0'} - - '@algolia/client-query-suggestions@5.54.0': - resolution: {integrity: sha512-AxW2MLBhjBtGX5kIZrVLO2SP2vRkZxJw5qHGxnQJfLcYhA04mFNP0fWRtHshlcVnDk9M8L9lwfr2lGpf3Er+hw==} - engines: {node: '>= 14.0.0'} - - '@algolia/client-search@5.54.0': - resolution: {integrity: sha512-ngdgVGp05lJzUyA+sUzr0MDZ7AMtANcJpwIzq4ZsfpZL5B3S7A4XYfMcU2sECZc3bx3ysOhYcdbbaTjc3ve0WQ==} - engines: {node: '>= 14.0.0'} - - '@algolia/ingestion@1.54.0': - resolution: {integrity: sha512-hee59Z7FgZ6/13FYL05ANPwRJY1pfvIlrwC8eBZYdiRFXTJVvf94IyTWOxLqRVpbseDP6eQQTW+PT7/DxTZIng==} - engines: {node: '>= 14.0.0'} - - '@algolia/monitoring@1.54.0': - resolution: {integrity: sha512-diCjZVbIO7Pzw98tEKqLWIAgmQBI3Zt1sHsXyAPNGZgn32derpIXTnjjpJbZl+uAhSSznd6SfxFGdC9uYdN1TA==} - engines: {node: '>= 14.0.0'} - - '@algolia/recommend@5.54.0': - resolution: {integrity: sha512-6zeslypRAGWDgVJEJYAPuqmyquHvnw4MQwG+XXdrw5dTNDjXYIcCJdQQcCY06xPF9tUvmzy/1vHiH9QxhgwuOQ==} - engines: {node: '>= 14.0.0'} - - '@algolia/requester-browser-xhr@5.54.0': - resolution: {integrity: sha512-iHZax214LPXd7XizQ4BNnTsegl8f3IeKm8JcrmSNZ/5x1rZ5xLkbG/anltAWtLpoRNnfpr4Z80YdYeVVPpx6wQ==} - engines: {node: '>= 14.0.0'} - - '@algolia/requester-fetch@5.54.0': - resolution: {integrity: sha512-YKtuG5YwPxZ+kkfd4HmUO7Z9aICPUSMlHslzKTmtMMhxGnetxEqGj9T/v2r/PdcuOUC5oW0CHe8akJk8cpS3gQ==} - engines: {node: '>= 14.0.0'} - - '@algolia/requester-node-http@5.54.0': - resolution: {integrity: sha512-zyZDJ4WS5TnjZZ5pqywTBFO9olW7QMtY2kf2dbLnu+UTzfc9ri/HGf27jRN2NTbX9FcRPxSqPqzUhF/BZIx0VA==} - engines: {node: '>= 14.0.0'} - - '@babel/helper-string-parser@7.29.7': - resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.29.7': - resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} - engines: {node: '>=6.9.0'} - - '@docsearch/css@3.8.2': - resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==} - - '@docsearch/js@3.8.2': - resolution: {integrity: sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==} - - '@docsearch/react@3.8.2': - resolution: {integrity: sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==} - peerDependencies: - '@types/react': '>= 16.8.0 < 19.0.0' - react: '>= 16.8.0 < 19.0.0' - react-dom: '>= 16.8.0 < 19.0.0' - search-insights: '>= 1 < 3' - peerDependenciesMeta: - '@types/react': - optional: true - react: - optional: true - react-dom: - optional: true - search-insights: - optional: true - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@iconify-json/simple-icons@1.2.86': - resolution: {integrity: sha512-t3jck5qPQuK1qy+bRn9eCoDQhIB7XSazKz1Fjp8hcan3XOAsTI5Mq/s3F0ekOKSvMQqkVORYK6ns6o6T9f5EMA==} - - '@iconify/types@2.0.0': - resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@rollup/rollup-android-arm-eabi@4.61.1': - resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.61.1': - resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.61.1': - resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.61.1': - resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.61.1': - resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.61.1': - resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': - resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.61.1': - resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.61.1': - resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.61.1': - resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-loong64-gnu@4.61.1': - resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.61.1': - resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.61.1': - resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-musl@4.61.1': - resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.61.1': - resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.61.1': - resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.61.1': - resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.61.1': - resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-musl@4.61.1': - resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-openbsd-x64@4.61.1': - resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.61.1': - resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.61.1': - resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.61.1': - resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.61.1': - resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.61.1': - resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} - cpu: [x64] - os: [win32] - - '@shikijs/core@2.5.0': - resolution: {integrity: sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==} - - '@shikijs/engine-javascript@2.5.0': - resolution: {integrity: sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==} - - '@shikijs/engine-oniguruma@2.5.0': - resolution: {integrity: sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==} - - '@shikijs/langs@2.5.0': - resolution: {integrity: sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==} - - '@shikijs/themes@2.5.0': - resolution: {integrity: sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==} - - '@shikijs/transformers@2.5.0': - resolution: {integrity: sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==} - - '@shikijs/types@2.5.0': - resolution: {integrity: sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==} - - '@shikijs/vscode-textmate@10.0.2': - resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/linkify-it@5.0.0': - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - - '@types/markdown-it@14.1.2': - resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/mdurl@2.0.0': - resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@types/web-bluetooth@0.0.21': - resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} - - '@ungap/structured-clone@1.3.1': - resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} - - '@vitejs/plugin-vue@5.2.4': - resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 - vue: ^3.2.25 - - '@vue/compiler-core@3.5.38': - resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} - - '@vue/compiler-dom@3.5.38': - resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} - - '@vue/compiler-sfc@3.5.38': - resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} - - '@vue/compiler-ssr@3.5.38': - resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} - - '@vue/devtools-api@7.7.9': - resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} - - '@vue/devtools-kit@7.7.9': - resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} - - '@vue/devtools-shared@7.7.9': - resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} - - '@vue/reactivity@3.5.38': - resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} - - '@vue/runtime-core@3.5.38': - resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} - - '@vue/runtime-dom@3.5.38': - resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} - - '@vue/server-renderer@3.5.38': - resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} - peerDependencies: - vue: 3.5.38 - - '@vue/shared@3.5.38': - resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} - - '@vueuse/core@12.8.2': - resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} - - '@vueuse/integrations@12.8.2': - resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==} - peerDependencies: - async-validator: ^4 - axios: ^1 - change-case: ^5 - drauu: ^0.4 - focus-trap: ^7 - fuse.js: ^7 - idb-keyval: ^6 - jwt-decode: ^4 - nprogress: ^0.2 - qrcode: ^1.5 - sortablejs: ^1 - universal-cookie: ^7 - peerDependenciesMeta: - async-validator: - optional: true - axios: - optional: true - change-case: - optional: true - drauu: - optional: true - focus-trap: - optional: true - fuse.js: - optional: true - idb-keyval: - optional: true - jwt-decode: - optional: true - nprogress: - optional: true - qrcode: - optional: true - sortablejs: - optional: true - universal-cookie: - optional: true - - '@vueuse/metadata@12.8.2': - resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} - - '@vueuse/shared@12.8.2': - resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} - - algoliasearch@5.54.0: - resolution: {integrity: sha512-APAX4ajIOgsmYoUlGe++oNZkSTBgmXYM4maHC0OxC+Yo7xkaKQElV0ATZYCZA7jzrSJX1OBiqEs7mk+ZxXgYqA==} - engines: {node: '>= 14.0.0'} - - birpc@2.9.0: - resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - copy-anything@4.0.5: - resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} - engines: {node: '>=18'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - emoji-regex-xs@1.0.0: - resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} - - entities@7.0.1: - resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} - engines: {node: '>=0.12'} - - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - focus-trap@7.8.0: - resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - hast-util-to-html@9.0.5: - resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hookable@5.5.3: - resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - is-what@5.5.0: - resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} - engines: {node: '>=18'} - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - mark.js@8.11.1: - resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} - - mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - minisearch@7.2.0: - resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==} - - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - oniguruma-to-es@3.1.1: - resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==} - - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} - engines: {node: ^10 || ^12 || >=14} - - preact@10.29.2: - resolution: {integrity: sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==} - - property-information@7.2.0: - resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} - - regex-recursion@6.0.2: - resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} - - regex-utilities@2.3.0: - resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - - regex@6.1.0: - resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} - - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - - rollup@4.61.1: - resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - search-insights@2.17.3: - resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} - - shiki@2.5.0: - resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - speakingurl@14.0.1: - resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} - engines: {node: '>=0.10.0'} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - superjson@2.2.6: - resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} - engines: {node: '>=16'} - - tabbable@6.4.0: - resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.1.0: - resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - vite@5.4.21: - resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vitepress@1.6.4: - resolution: {integrity: sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==} - hasBin: true - peerDependencies: - markdown-it-mathjax3: ^4 - postcss: ^8 - peerDependenciesMeta: - markdown-it-mathjax3: - optional: true - postcss: - optional: true - - vue@3.5.38: - resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@algolia/abtesting@1.20.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3)': - dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3) - '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) - transitivePeerDependencies: - - '@algolia/client-search' - - algoliasearch - - search-insights - - '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3)': - dependencies: - '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) - search-insights: 2.17.3 - transitivePeerDependencies: - - '@algolia/client-search' - - algoliasearch - - '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)': - dependencies: - '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) - '@algolia/client-search': 5.54.0 - algoliasearch: 5.54.0 - - '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)': - dependencies: - '@algolia/client-search': 5.54.0 - algoliasearch: 5.54.0 - - '@algolia/client-abtesting@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/client-analytics@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/client-common@5.54.0': {} - - '@algolia/client-insights@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/client-personalization@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/client-query-suggestions@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/client-search@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/ingestion@1.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/monitoring@1.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/recommend@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - '@algolia/requester-browser-xhr@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - - '@algolia/requester-fetch@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - - '@algolia/requester-node-http@5.54.0': - dependencies: - '@algolia/client-common': 5.54.0 - - '@babel/helper-string-parser@7.29.7': {} - - '@babel/helper-validator-identifier@7.29.7': {} - - '@babel/parser@7.29.7': - dependencies: - '@babel/types': 7.29.7 - - '@babel/types@7.29.7': - dependencies: - '@babel/helper-string-parser': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - - '@docsearch/css@3.8.2': {} - - '@docsearch/js@3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3)': - dependencies: - '@docsearch/react': 3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3) - preact: 10.29.2 - transitivePeerDependencies: - - '@algolia/client-search' - - '@types/react' - - react - - react-dom - - search-insights - - '@docsearch/react@3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3)': - dependencies: - '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0)(search-insights@2.17.3) - '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.54.0)(algoliasearch@5.54.0) - '@docsearch/css': 3.8.2 - algoliasearch: 5.54.0 - optionalDependencies: - search-insights: 2.17.3 - transitivePeerDependencies: - - '@algolia/client-search' - - '@esbuild/aix-ppc64@0.21.5': - optional: true - - '@esbuild/android-arm64@0.21.5': - optional: true - - '@esbuild/android-arm@0.21.5': - optional: true - - '@esbuild/android-x64@0.21.5': - optional: true - - '@esbuild/darwin-arm64@0.21.5': - optional: true - - '@esbuild/darwin-x64@0.21.5': - optional: true - - '@esbuild/freebsd-arm64@0.21.5': - optional: true - - '@esbuild/freebsd-x64@0.21.5': - optional: true - - '@esbuild/linux-arm64@0.21.5': - optional: true - - '@esbuild/linux-arm@0.21.5': - optional: true - - '@esbuild/linux-ia32@0.21.5': - optional: true - - '@esbuild/linux-loong64@0.21.5': - optional: true - - '@esbuild/linux-mips64el@0.21.5': - optional: true - - '@esbuild/linux-ppc64@0.21.5': - optional: true - - '@esbuild/linux-riscv64@0.21.5': - optional: true - - '@esbuild/linux-s390x@0.21.5': - optional: true - - '@esbuild/linux-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/openbsd-x64@0.21.5': - optional: true - - '@esbuild/sunos-x64@0.21.5': - optional: true - - '@esbuild/win32-arm64@0.21.5': - optional: true - - '@esbuild/win32-ia32@0.21.5': - optional: true - - '@esbuild/win32-x64@0.21.5': - optional: true - - '@iconify-json/simple-icons@1.2.86': - dependencies: - '@iconify/types': 2.0.0 - - '@iconify/types@2.0.0': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@rollup/rollup-android-arm-eabi@4.61.1': - optional: true - - '@rollup/rollup-android-arm64@4.61.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.61.1': - optional: true - - '@rollup/rollup-darwin-x64@4.61.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.61.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.61.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.61.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.61.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.61.1': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.61.1': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.61.1': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.61.1': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.61.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.61.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.61.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.61.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.61.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.61.1': - optional: true - - '@rollup/rollup-openbsd-x64@4.61.1': - optional: true - - '@rollup/rollup-openharmony-arm64@4.61.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.61.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.61.1': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.61.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.61.1': - optional: true - - '@shikijs/core@2.5.0': - dependencies: - '@shikijs/engine-javascript': 2.5.0 - '@shikijs/engine-oniguruma': 2.5.0 - '@shikijs/types': 2.5.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - hast-util-to-html: 9.0.5 - - '@shikijs/engine-javascript@2.5.0': - dependencies: - '@shikijs/types': 2.5.0 - '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 3.1.1 - - '@shikijs/engine-oniguruma@2.5.0': - dependencies: - '@shikijs/types': 2.5.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/langs@2.5.0': - dependencies: - '@shikijs/types': 2.5.0 - - '@shikijs/themes@2.5.0': - dependencies: - '@shikijs/types': 2.5.0 - - '@shikijs/transformers@2.5.0': - dependencies: - '@shikijs/core': 2.5.0 - '@shikijs/types': 2.5.0 - - '@shikijs/types@2.5.0': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/vscode-textmate@10.0.2': {} - - '@types/estree@1.0.9': {} - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/linkify-it@5.0.0': {} - - '@types/markdown-it@14.1.2': - dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/mdurl@2.0.0': {} - - '@types/unist@3.0.3': {} - - '@types/web-bluetooth@0.0.21': {} - - '@ungap/structured-clone@1.3.1': {} - - '@vitejs/plugin-vue@5.2.4(vite@5.4.21)(vue@3.5.38)': - dependencies: - vite: 5.4.21 - vue: 3.5.38 - - '@vue/compiler-core@3.5.38': - dependencies: - '@babel/parser': 7.29.7 - '@vue/shared': 3.5.38 - entities: 7.0.1 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - '@vue/compiler-dom@3.5.38': - dependencies: - '@vue/compiler-core': 3.5.38 - '@vue/shared': 3.5.38 - - '@vue/compiler-sfc@3.5.38': - dependencies: - '@babel/parser': 7.29.7 - '@vue/compiler-core': 3.5.38 - '@vue/compiler-dom': 3.5.38 - '@vue/compiler-ssr': 3.5.38 - '@vue/shared': 3.5.38 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.15 - source-map-js: 1.2.1 - - '@vue/compiler-ssr@3.5.38': - dependencies: - '@vue/compiler-dom': 3.5.38 - '@vue/shared': 3.5.38 - - '@vue/devtools-api@7.7.9': - dependencies: - '@vue/devtools-kit': 7.7.9 - - '@vue/devtools-kit@7.7.9': - dependencies: - '@vue/devtools-shared': 7.7.9 - birpc: 2.9.0 - hookable: 5.5.3 - mitt: 3.0.1 - perfect-debounce: 1.0.0 - speakingurl: 14.0.1 - superjson: 2.2.6 - - '@vue/devtools-shared@7.7.9': - dependencies: - rfdc: 1.4.1 - - '@vue/reactivity@3.5.38': - dependencies: - '@vue/shared': 3.5.38 - - '@vue/runtime-core@3.5.38': - dependencies: - '@vue/reactivity': 3.5.38 - '@vue/shared': 3.5.38 - - '@vue/runtime-dom@3.5.38': - dependencies: - '@vue/reactivity': 3.5.38 - '@vue/runtime-core': 3.5.38 - '@vue/shared': 3.5.38 - csstype: 3.2.3 - - '@vue/server-renderer@3.5.38(vue@3.5.38)': - dependencies: - '@vue/compiler-ssr': 3.5.38 - '@vue/shared': 3.5.38 - vue: 3.5.38 - - '@vue/shared@3.5.38': {} - - '@vueuse/core@12.8.2': - dependencies: - '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 12.8.2 - '@vueuse/shared': 12.8.2 - vue: 3.5.38 - transitivePeerDependencies: - - typescript - - '@vueuse/integrations@12.8.2(focus-trap@7.8.0)': - dependencies: - '@vueuse/core': 12.8.2 - '@vueuse/shared': 12.8.2 - vue: 3.5.38 - optionalDependencies: - focus-trap: 7.8.0 - transitivePeerDependencies: - - typescript - - '@vueuse/metadata@12.8.2': {} - - '@vueuse/shared@12.8.2': - dependencies: - vue: 3.5.38 - transitivePeerDependencies: - - typescript - - algoliasearch@5.54.0: - dependencies: - '@algolia/abtesting': 1.20.0 - '@algolia/client-abtesting': 5.54.0 - '@algolia/client-analytics': 5.54.0 - '@algolia/client-common': 5.54.0 - '@algolia/client-insights': 5.54.0 - '@algolia/client-personalization': 5.54.0 - '@algolia/client-query-suggestions': 5.54.0 - '@algolia/client-search': 5.54.0 - '@algolia/ingestion': 1.54.0 - '@algolia/monitoring': 1.54.0 - '@algolia/recommend': 5.54.0 - '@algolia/requester-browser-xhr': 5.54.0 - '@algolia/requester-fetch': 5.54.0 - '@algolia/requester-node-http': 5.54.0 - - birpc@2.9.0: {} - - ccount@2.0.1: {} - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - comma-separated-tokens@2.0.3: {} - - copy-anything@4.0.5: - dependencies: - is-what: 5.5.0 - - csstype@3.2.3: {} - - dequal@2.0.3: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - emoji-regex-xs@1.0.0: {} - - entities@7.0.1: {} - - esbuild@0.21.5: - optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 - - estree-walker@2.0.2: {} - - focus-trap@7.8.0: - dependencies: - tabbable: 6.4.0 - - fsevents@2.3.3: - optional: true - - hast-util-to-html@9.0.5: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 3.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - property-information: 7.2.0 - space-separated-tokens: 2.0.2 - stringify-entities: 4.0.4 - zwitch: 2.0.4 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hookable@5.5.3: {} - - html-void-elements@3.0.0: {} - - is-what@5.5.0: {} - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - mark.js@8.11.1: {} - - mdast-util-to-hast@13.2.1: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.1 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-encode@2.0.1: {} - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - minisearch@7.2.0: {} - - mitt@3.0.1: {} - - nanoid@3.3.12: {} - - oniguruma-to-es@3.1.1: - dependencies: - emoji-regex-xs: 1.0.0 - regex: 6.1.0 - regex-recursion: 6.0.2 - - perfect-debounce@1.0.0: {} - - picocolors@1.1.1: {} - - postcss@8.5.15: - dependencies: - nanoid: 3.3.12 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - preact@10.29.2: {} - - property-information@7.2.0: {} - - regex-recursion@6.0.2: - dependencies: - regex-utilities: 2.3.0 - - regex-utilities@2.3.0: {} - - regex@6.1.0: - dependencies: - regex-utilities: 2.3.0 - - rfdc@1.4.1: {} - - rollup@4.61.1: - dependencies: - '@types/estree': 1.0.9 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.61.1 - '@rollup/rollup-android-arm64': 4.61.1 - '@rollup/rollup-darwin-arm64': 4.61.1 - '@rollup/rollup-darwin-x64': 4.61.1 - '@rollup/rollup-freebsd-arm64': 4.61.1 - '@rollup/rollup-freebsd-x64': 4.61.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 - '@rollup/rollup-linux-arm-musleabihf': 4.61.1 - '@rollup/rollup-linux-arm64-gnu': 4.61.1 - '@rollup/rollup-linux-arm64-musl': 4.61.1 - '@rollup/rollup-linux-loong64-gnu': 4.61.1 - '@rollup/rollup-linux-loong64-musl': 4.61.1 - '@rollup/rollup-linux-ppc64-gnu': 4.61.1 - '@rollup/rollup-linux-ppc64-musl': 4.61.1 - '@rollup/rollup-linux-riscv64-gnu': 4.61.1 - '@rollup/rollup-linux-riscv64-musl': 4.61.1 - '@rollup/rollup-linux-s390x-gnu': 4.61.1 - '@rollup/rollup-linux-x64-gnu': 4.61.1 - '@rollup/rollup-linux-x64-musl': 4.61.1 - '@rollup/rollup-openbsd-x64': 4.61.1 - '@rollup/rollup-openharmony-arm64': 4.61.1 - '@rollup/rollup-win32-arm64-msvc': 4.61.1 - '@rollup/rollup-win32-ia32-msvc': 4.61.1 - '@rollup/rollup-win32-x64-gnu': 4.61.1 - '@rollup/rollup-win32-x64-msvc': 4.61.1 - fsevents: 2.3.3 - - search-insights@2.17.3: {} - - shiki@2.5.0: - dependencies: - '@shikijs/core': 2.5.0 - '@shikijs/engine-javascript': 2.5.0 - '@shikijs/engine-oniguruma': 2.5.0 - '@shikijs/langs': 2.5.0 - '@shikijs/themes': 2.5.0 - '@shikijs/types': 2.5.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - source-map-js@1.2.1: {} - - space-separated-tokens@2.0.2: {} - - speakingurl@14.0.1: {} - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - superjson@2.2.6: - dependencies: - copy-anything: 4.0.5 - - tabbable@6.4.0: {} - - trim-lines@3.0.1: {} - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.1.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - vite@5.4.21: - dependencies: - esbuild: 0.21.5 - postcss: 8.5.15 - rollup: 4.61.1 - optionalDependencies: - fsevents: 2.3.3 - - vitepress@1.6.4(@algolia/client-search@5.54.0)(postcss@8.5.15)(search-insights@2.17.3): - dependencies: - '@docsearch/css': 3.8.2 - '@docsearch/js': 3.8.2(@algolia/client-search@5.54.0)(search-insights@2.17.3) - '@iconify-json/simple-icons': 1.2.86 - '@shikijs/core': 2.5.0 - '@shikijs/transformers': 2.5.0 - '@shikijs/types': 2.5.0 - '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 5.2.4(vite@5.4.21)(vue@3.5.38) - '@vue/devtools-api': 7.7.9 - '@vue/shared': 3.5.38 - '@vueuse/core': 12.8.2 - '@vueuse/integrations': 12.8.2(focus-trap@7.8.0) - focus-trap: 7.8.0 - mark.js: 8.11.1 - minisearch: 7.2.0 - shiki: 2.5.0 - vite: 5.4.21 - vue: 3.5.38 - optionalDependencies: - postcss: 8.5.15 - transitivePeerDependencies: - - '@algolia/client-search' - - '@types/node' - - '@types/react' - - async-validator - - axios - - change-case - - drauu - - fuse.js - - idb-keyval - - jwt-decode - - less - - lightningcss - - nprogress - - qrcode - - react - - react-dom - - sass - - sass-embedded - - search-insights - - sortablejs - - stylus - - sugarss - - terser - - typescript - - universal-cookie - - vue@3.5.38: - dependencies: - '@vue/compiler-dom': 3.5.38 - '@vue/compiler-sfc': 3.5.38 - '@vue/runtime-dom': 3.5.38 - '@vue/server-renderer': 3.5.38(vue@3.5.38) - '@vue/shared': 3.5.38 - - zwitch@2.0.4: {} diff --git a/docs/_internal/review/config-completion-findings.md b/docs/review/config-completion-findings.md similarity index 99% rename from docs/_internal/review/config-completion-findings.md rename to docs/review/config-completion-findings.md index 5f9f45a..f5227b1 100644 --- a/docs/_internal/review/config-completion-findings.md +++ b/docs/review/config-completion-findings.md @@ -26,6 +26,7 @@ Légende statut : [ ] à faire · [x] fait - un champ **avec** `defaultValue` est toujours présent → **pas** de `| undefined`. - **Fix proposé :** - Typage conditionnel sur la présence de `defaultValue` : + ```ts type ConfigEntryValue> = E extends { defaultValue: unknown; @@ -33,7 +34,9 @@ Légende statut : [ ] à faire · [x] fait ? ResolveType : ResolveType | undefined; ``` + utilisé par `ConfigData` et `ConfigProvider.get`. + - Runtime : `createDefaultConfigForModule` ne pose une valeur que si `defaultValue` est déclaré (sinon clé absente → `undefined`), au lieu de fabriquer `""`/`0`/`false`/`null`. diff --git a/docs/_internal/review/dev-guild-commands-findings.md b/docs/review/dev-guild-commands-findings.md similarity index 100% rename from docs/_internal/review/dev-guild-commands-findings.md rename to docs/review/dev-guild-commands-findings.md diff --git a/docs/.gitignore b/docs/site/.gitignore similarity index 100% rename from docs/.gitignore rename to docs/site/.gitignore diff --git a/docs/.vitepress/config.ts b/docs/site/.vitepress/config.ts similarity index 93% rename from docs/.vitepress/config.ts rename to docs/site/.vitepress/config.ts index 22c6fc8..f4515dc 100644 --- a/docs/.vitepress/config.ts +++ b/docs/site/.vitepress/config.ts @@ -8,19 +8,7 @@ export default defineConfig({ title: "OmniBot", description: "Documentation du bot Discord modulaire OmniBot", - srcExclude: [ - "README.md", - "functional.md", - "modules.md", - "commands.md", - "listeners.md", - "interactions.md", - "services.md", - "prisma.md", - "specs/**", - "review/**", - "_internal/**", - ], + srcExclude: ["README.md"], cleanUrls: true, diff --git a/docs/README.md b/docs/site/README.md similarity index 50% rename from docs/README.md rename to docs/site/README.md index 8d0f5c2..1d9075d 100644 --- a/docs/README.md +++ b/docs/site/README.md @@ -5,19 +5,20 @@ La documentation a été migrée vers [VitePress](https://vitepress.dev/). Pour lancer le serveur de documentation en local : ```bash -pnpm --filter docs dev +pnpm --filter omnibot-docs dev ``` Pour construire la version statique : ```bash -pnpm --filter docs build +pnpm --filter omnibot-docs build ``` -Les sources sont organisées dans `docs/` : +Les sources du site sont organisées dans `docs/site/` : - `en/` — Documentation en anglais - `fr/` — Documentation en français -- `_internal/` — Anciens fichiers et spécifications internes -> L'ancienne documentation markdown simple a été déplacée dans `docs/_internal/`. +> Les anciennes notes internes (spécifications, revues, comportement +> fonctionnel) restent en markdown simple dans `docs/` (`functional.md`, +> `specs/`, `review/`). diff --git a/docs/en/guide/configuration.md b/docs/site/en/guide/configuration.md similarity index 100% rename from docs/en/guide/configuration.md rename to docs/site/en/guide/configuration.md diff --git a/docs/en/guide/creating-a-module.md b/docs/site/en/guide/creating-a-module.md similarity index 100% rename from docs/en/guide/creating-a-module.md rename to docs/site/en/guide/creating-a-module.md diff --git a/docs/en/guide/database.md b/docs/site/en/guide/database.md similarity index 100% rename from docs/en/guide/database.md rename to docs/site/en/guide/database.md diff --git a/docs/en/guide/getting-started.md b/docs/site/en/guide/getting-started.md similarity index 100% rename from docs/en/guide/getting-started.md rename to docs/site/en/guide/getting-started.md diff --git a/docs/en/guide/listeners.md b/docs/site/en/guide/listeners.md similarity index 100% rename from docs/en/guide/listeners.md rename to docs/site/en/guide/listeners.md diff --git a/docs/en/guide/services.md b/docs/site/en/guide/services.md similarity index 100% rename from docs/en/guide/services.md rename to docs/site/en/guide/services.md diff --git a/docs/en/index.md b/docs/site/en/index.md similarity index 100% rename from docs/en/index.md rename to docs/site/en/index.md diff --git a/docs/fr/guide/configuration.md b/docs/site/fr/guide/configuration.md similarity index 100% rename from docs/fr/guide/configuration.md rename to docs/site/fr/guide/configuration.md diff --git a/docs/fr/guide/creating-a-module.md b/docs/site/fr/guide/creating-a-module.md similarity index 100% rename from docs/fr/guide/creating-a-module.md rename to docs/site/fr/guide/creating-a-module.md diff --git a/docs/fr/guide/database.md b/docs/site/fr/guide/database.md similarity index 100% rename from docs/fr/guide/database.md rename to docs/site/fr/guide/database.md diff --git a/docs/fr/guide/getting-started.md b/docs/site/fr/guide/getting-started.md similarity index 100% rename from docs/fr/guide/getting-started.md rename to docs/site/fr/guide/getting-started.md diff --git a/docs/fr/guide/listeners.md b/docs/site/fr/guide/listeners.md similarity index 100% rename from docs/fr/guide/listeners.md rename to docs/site/fr/guide/listeners.md diff --git a/docs/fr/guide/services.md b/docs/site/fr/guide/services.md similarity index 100% rename from docs/fr/guide/services.md rename to docs/site/fr/guide/services.md diff --git a/docs/fr/index.md b/docs/site/fr/index.md similarity index 100% rename from docs/fr/index.md rename to docs/site/fr/index.md diff --git a/docs/package.json b/docs/site/package.json similarity index 100% rename from docs/package.json rename to docs/site/package.json diff --git a/docs/_internal/specs/autopin.md b/docs/specs/autopin.md similarity index 100% rename from docs/_internal/specs/autopin.md rename to docs/specs/autopin.md diff --git a/docs/_internal/specs/module-config.md b/docs/specs/module-config.md similarity index 100% rename from docs/_internal/specs/module-config.md rename to docs/specs/module-config.md diff --git a/docs/_internal/specs/thread-creator-queue.md b/docs/specs/thread-creator-queue.md similarity index 100% rename from docs/_internal/specs/thread-creator-queue.md rename to docs/specs/thread-creator-queue.md diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47800b9..f9a0470 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,7 +56,7 @@ importers: specifier: ^4.1.8 version: 4.1.8(@types/node@24.13.2)(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.4)(yaml@2.9.0)) - docs: + docs/site: dependencies: vitepress: specifier: ^1.6.4 @@ -993,141 +993,141 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/rollup-android-arm-eabi@4.61.1': - resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} + '@rollup/rollup-android-arm-eabi@4.62.0': + resolution: {integrity: sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.61.1': - resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} + '@rollup/rollup-android-arm64@4.62.0': + resolution: {integrity: sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.61.1': - resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} + '@rollup/rollup-darwin-arm64@4.62.0': + resolution: {integrity: sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.61.1': - resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} + '@rollup/rollup-darwin-x64@4.62.0': + resolution: {integrity: sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.61.1': - resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} + '@rollup/rollup-freebsd-arm64@4.62.0': + resolution: {integrity: sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.61.1': - resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} + '@rollup/rollup-freebsd-x64@4.62.0': + resolution: {integrity: sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': - resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.0': + resolution: {integrity: sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.61.1': - resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} + '@rollup/rollup-linux-arm-musleabihf@4.62.0': + resolution: {integrity: sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.61.1': - resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} + '@rollup/rollup-linux-arm64-gnu@4.62.0': + resolution: {integrity: sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.61.1': - resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} + '@rollup/rollup-linux-arm64-musl@4.62.0': + resolution: {integrity: sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.61.1': - resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} + '@rollup/rollup-linux-loong64-gnu@4.62.0': + resolution: {integrity: sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.61.1': - resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} + '@rollup/rollup-linux-loong64-musl@4.62.0': + resolution: {integrity: sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.61.1': - resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} + '@rollup/rollup-linux-ppc64-gnu@4.62.0': + resolution: {integrity: sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.61.1': - resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} + '@rollup/rollup-linux-ppc64-musl@4.62.0': + resolution: {integrity: sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.61.1': - resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} + '@rollup/rollup-linux-riscv64-gnu@4.62.0': + resolution: {integrity: sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.61.1': - resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} + '@rollup/rollup-linux-riscv64-musl@4.62.0': + resolution: {integrity: sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.61.1': - resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} + '@rollup/rollup-linux-s390x-gnu@4.62.0': + resolution: {integrity: sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.61.1': - resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} + '@rollup/rollup-linux-x64-gnu@4.62.0': + resolution: {integrity: sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.61.1': - resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} + '@rollup/rollup-linux-x64-musl@4.62.0': + resolution: {integrity: sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.61.1': - resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} + '@rollup/rollup-openbsd-x64@4.62.0': + resolution: {integrity: sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.61.1': - resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} + '@rollup/rollup-openharmony-arm64@4.62.0': + resolution: {integrity: sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.61.1': - resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} + '@rollup/rollup-win32-arm64-msvc@4.62.0': + resolution: {integrity: sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.61.1': - resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} + '@rollup/rollup-win32-ia32-msvc@4.62.0': + resolution: {integrity: sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.61.1': - resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} + '@rollup/rollup-win32-x64-gnu@4.62.0': + resolution: {integrity: sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.61.1': - resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} + '@rollup/rollup-win32-x64-msvc@4.62.0': + resolution: {integrity: sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==} cpu: [x64] os: [win32] @@ -2037,8 +2037,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.61.1: - resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} + rollup@4.62.0: + resolution: {integrity: sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3064,79 +3064,79 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} - '@rollup/rollup-android-arm-eabi@4.61.1': + '@rollup/rollup-android-arm-eabi@4.62.0': optional: true - '@rollup/rollup-android-arm64@4.61.1': + '@rollup/rollup-android-arm64@4.62.0': optional: true - '@rollup/rollup-darwin-arm64@4.61.1': + '@rollup/rollup-darwin-arm64@4.62.0': optional: true - '@rollup/rollup-darwin-x64@4.61.1': + '@rollup/rollup-darwin-x64@4.62.0': optional: true - '@rollup/rollup-freebsd-arm64@4.61.1': + '@rollup/rollup-freebsd-arm64@4.62.0': optional: true - '@rollup/rollup-freebsd-x64@4.61.1': + '@rollup/rollup-freebsd-x64@4.62.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + '@rollup/rollup-linux-arm-gnueabihf@4.62.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.61.1': + '@rollup/rollup-linux-arm-musleabihf@4.62.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.61.1': + '@rollup/rollup-linux-arm64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.61.1': + '@rollup/rollup-linux-arm64-musl@4.62.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.61.1': + '@rollup/rollup-linux-loong64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.61.1': + '@rollup/rollup-linux-loong64-musl@4.62.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.61.1': + '@rollup/rollup-linux-ppc64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.61.1': + '@rollup/rollup-linux-ppc64-musl@4.62.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.61.1': + '@rollup/rollup-linux-riscv64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.61.1': + '@rollup/rollup-linux-riscv64-musl@4.62.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.61.1': + '@rollup/rollup-linux-s390x-gnu@4.62.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.61.1': + '@rollup/rollup-linux-x64-gnu@4.62.0': optional: true - '@rollup/rollup-linux-x64-musl@4.61.1': + '@rollup/rollup-linux-x64-musl@4.62.0': optional: true - '@rollup/rollup-openbsd-x64@4.61.1': + '@rollup/rollup-openbsd-x64@4.62.0': optional: true - '@rollup/rollup-openharmony-arm64@4.61.1': + '@rollup/rollup-openharmony-arm64@4.62.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.61.1': + '@rollup/rollup-win32-arm64-msvc@4.62.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.61.1': + '@rollup/rollup-win32-ia32-msvc@4.62.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.61.1': + '@rollup/rollup-win32-x64-gnu@4.62.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.61.1': + '@rollup/rollup-win32-x64-msvc@4.62.0': optional: true '@sapphire/async-queue@1.5.5': {} @@ -4113,35 +4113,35 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.3 '@rolldown/binding-win32-x64-msvc': 1.0.3 - rollup@4.61.1: + rollup@4.62.0: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.61.1 - '@rollup/rollup-android-arm64': 4.61.1 - '@rollup/rollup-darwin-arm64': 4.61.1 - '@rollup/rollup-darwin-x64': 4.61.1 - '@rollup/rollup-freebsd-arm64': 4.61.1 - '@rollup/rollup-freebsd-x64': 4.61.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 - '@rollup/rollup-linux-arm-musleabihf': 4.61.1 - '@rollup/rollup-linux-arm64-gnu': 4.61.1 - '@rollup/rollup-linux-arm64-musl': 4.61.1 - '@rollup/rollup-linux-loong64-gnu': 4.61.1 - '@rollup/rollup-linux-loong64-musl': 4.61.1 - '@rollup/rollup-linux-ppc64-gnu': 4.61.1 - '@rollup/rollup-linux-ppc64-musl': 4.61.1 - '@rollup/rollup-linux-riscv64-gnu': 4.61.1 - '@rollup/rollup-linux-riscv64-musl': 4.61.1 - '@rollup/rollup-linux-s390x-gnu': 4.61.1 - '@rollup/rollup-linux-x64-gnu': 4.61.1 - '@rollup/rollup-linux-x64-musl': 4.61.1 - '@rollup/rollup-openbsd-x64': 4.61.1 - '@rollup/rollup-openharmony-arm64': 4.61.1 - '@rollup/rollup-win32-arm64-msvc': 4.61.1 - '@rollup/rollup-win32-ia32-msvc': 4.61.1 - '@rollup/rollup-win32-x64-gnu': 4.61.1 - '@rollup/rollup-win32-x64-msvc': 4.61.1 + '@rollup/rollup-android-arm-eabi': 4.62.0 + '@rollup/rollup-android-arm64': 4.62.0 + '@rollup/rollup-darwin-arm64': 4.62.0 + '@rollup/rollup-darwin-x64': 4.62.0 + '@rollup/rollup-freebsd-arm64': 4.62.0 + '@rollup/rollup-freebsd-x64': 4.62.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.0 + '@rollup/rollup-linux-arm-musleabihf': 4.62.0 + '@rollup/rollup-linux-arm64-gnu': 4.62.0 + '@rollup/rollup-linux-arm64-musl': 4.62.0 + '@rollup/rollup-linux-loong64-gnu': 4.62.0 + '@rollup/rollup-linux-loong64-musl': 4.62.0 + '@rollup/rollup-linux-ppc64-gnu': 4.62.0 + '@rollup/rollup-linux-ppc64-musl': 4.62.0 + '@rollup/rollup-linux-riscv64-gnu': 4.62.0 + '@rollup/rollup-linux-riscv64-musl': 4.62.0 + '@rollup/rollup-linux-s390x-gnu': 4.62.0 + '@rollup/rollup-linux-x64-gnu': 4.62.0 + '@rollup/rollup-linux-x64-musl': 4.62.0 + '@rollup/rollup-openbsd-x64': 4.62.0 + '@rollup/rollup-openharmony-arm64': 4.62.0 + '@rollup/rollup-win32-arm64-msvc': 4.62.0 + '@rollup/rollup-win32-ia32-msvc': 4.62.0 + '@rollup/rollup-win32-x64-gnu': 4.62.0 + '@rollup/rollup-win32-x64-msvc': 4.62.0 fsevents: 2.3.3 safe-stable-stringify@2.5.0: {} @@ -4276,7 +4276,7 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.5.15 - rollup: 4.61.1 + rollup: 4.62.0 optionalDependencies: '@types/node': 24.13.2 fsevents: 2.3.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4e50d0a..f4569b0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,6 @@ packages: - "." - - "docs" + - "docs/site" allowBuilds: '@prisma/client': true From 783b2720eb3ec7feb60bf83fc0a4371700ac22c3 Mon Sep 17 00:00:00 2001 From: Antoine James Tournepiche Date: Sun, 14 Jun 2026 15:27:31 +0200 Subject: [PATCH 11/14] docs: correct Command and InteractionHandler API snippets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `config` is a required parameter — drop the misleading `config?`. - `InteractionHandler`: use `args: string[]` instead of the invalid `args[]` and declare the `Interaction` generic (was an undefined `T`). - Applies to both the EN and FR guides. Addresses the Copilot review. Co-Authored-By: Claude Opus 4.8 --- docs/{ => site}/en/guide/commands.md | 6 ++++-- docs/{ => site}/en/guide/interactions.md | 18 ++++++++++++------ docs/{ => site}/fr/guide/commands.md | 6 ++++-- docs/{ => site}/fr/guide/interactions.md | 18 ++++++++++++------ 4 files changed, 32 insertions(+), 16 deletions(-) rename docs/{ => site}/en/guide/commands.md (95%) rename docs/{ => site}/en/guide/interactions.md (93%) rename docs/{ => site}/fr/guide/commands.md (95%) rename docs/{ => site}/fr/guide/interactions.md (93%) diff --git a/docs/en/guide/commands.md b/docs/site/en/guide/commands.md similarity index 95% rename from docs/en/guide/commands.md rename to docs/site/en/guide/commands.md index 1d0a88a..56e920b 100644 --- a/docs/en/guide/commands.md +++ b/docs/site/en/guide/commands.md @@ -27,12 +27,14 @@ export default declareCommand({ interface Command { data: SlashCommandBuilder; // Command configuration execute: ( + // Execution function (required) interaction, - config? // Execution function (required) + config ) => Promise; complete?: ( + // Autocomplete (optional) interaction, - config? // Autocomplete (optional) + config ) => Promise; } ``` diff --git a/docs/en/guide/interactions.md b/docs/site/en/guide/interactions.md similarity index 93% rename from docs/en/guide/interactions.md rename to docs/site/en/guide/interactions.md index 876ab5b..3b824e3 100644 --- a/docs/en/guide/interactions.md +++ b/docs/site/en/guide/interactions.md @@ -25,12 +25,18 @@ src/modules/my-module/ ## API ```typescript -interface InteractionHandler { - customId: string; // Unique identifier - requiresAdmin?: boolean; // Admin-only - check: (interaction) => interaction is T; // Type check - execute: (interaction, args[], config?) // Execution function - => Promise; +interface InteractionHandler { + customId: string; // Unique identifier + requiresAdmin?: boolean; // Admin-only + check: ( + interaction, + config // Type guard + ) => interaction is Interaction; + execute: ( + interaction, + args: string[], + config // Execution function + ) => Promise; } ``` diff --git a/docs/fr/guide/commands.md b/docs/site/fr/guide/commands.md similarity index 95% rename from docs/fr/guide/commands.md rename to docs/site/fr/guide/commands.md index 5ba62d8..0a448e0 100644 --- a/docs/fr/guide/commands.md +++ b/docs/site/fr/guide/commands.md @@ -27,12 +27,14 @@ export default declareCommand({ interface Command { data: SlashCommandBuilder; // Configuration de la commande execute: ( + // Fonction d'exécution (obligatoire) interaction, - config? // Fonction d'exécution (obligatoire) + config ) => Promise; complete?: ( + // Autocomplétion (optionnelle) interaction, - config? // Autocomplétion (optionnelle) + config ) => Promise; } ``` diff --git a/docs/fr/guide/interactions.md b/docs/site/fr/guide/interactions.md similarity index 93% rename from docs/fr/guide/interactions.md rename to docs/site/fr/guide/interactions.md index 1e17d31..1d395aa 100644 --- a/docs/fr/guide/interactions.md +++ b/docs/site/fr/guide/interactions.md @@ -25,12 +25,18 @@ src/modules/mon-module/ ## API ```typescript -interface InteractionHandler { - customId: string; // Identifiant unique - requiresAdmin?: boolean; // Réservé aux admins - check: (interaction) => interaction is T; // Vérification du type - execute: (interaction, args[], config?) // Fonction d'exécution - => Promise; +interface InteractionHandler { + customId: string; // Identifiant unique + requiresAdmin?: boolean; // Réservé aux admins + check: ( + interaction, + config // Garde de type + ) => interaction is Interaction; + execute: ( + interaction, + args: string[], + config // Fonction d'exécution + ) => Promise; } ``` From bb9bc6388c82aa73495b030d90baf135cb2313cc Mon Sep 17 00:00:00 2001 From: Antoine James Tournepiche Date: Sun, 14 Jun 2026 15:27:40 +0200 Subject: [PATCH 12/14] ci(docs): harden the GitHub Pages workflow - Fix the artifact path to `docs/site/.vitepress/dist` after the move. - Add the `github-pages` environment to the deploy job. - Build on pull requests too; keep deploy gated to master pushes. - Scope the install with `--filter omnibot-docs` and restrict the `pages`/`id-token` permissions to the deploy job. - Bump and pin actions per the Renovate policy (checkout v6, upload-pages v5, deploy-pages v5, mise-action pinned to its commit SHA). - Factor the duplicated `paths` and deploy condition with YAML anchors. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/docs.yml | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3dd3552..d57bf98 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,41 +3,49 @@ name: Deploy docs to GitHub Pages on: push: branches: [master] - paths: + paths: &doc-paths - "docs/**" - ".github/workflows/docs.yml" + pull_request: + paths: *doc-paths workflow_dispatch: permissions: contents: read - pages: write - id-token: write concurrency: - group: pages - cancel-in-progress: false + group: pages-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - uses: jdx/mise-action@v2 + - uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0 - - run: pnpm install --frozen-lockfile + - run: pnpm install --frozen-lockfile --filter omnibot-docs - run: pnpm --filter omnibot-docs build env: DOCS_BASE: /OmniBot/ - - uses: actions/upload-pages-artifact@v3 + - if: &deploy-condition github.event_name == 'push' && github.ref == 'refs/heads/master' + uses: actions/upload-pages-artifact@v5 with: - path: docs/.vitepress/dist + path: docs/site/.vitepress/dist deploy: needs: build + if: *deploy-condition runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/deploy-pages@v4 + - uses: actions/deploy-pages@v5 id: deployment From 78902b3257ae5d0883b14d6af17710236573577c Mon Sep 17 00:00:00 2001 From: Antoine James Tournepiche Date: Sun, 14 Jun 2026 15:27:51 +0200 Subject: [PATCH 13/14] docs: drop broken hero logo and update audit backlog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove the `/logo.svg` hero reference (no asset yet); tracked as `#31`. - Record the `#28` decision: keep the current CI setup rather than adopt `jdx/mise-action` (would lose setup-node's pnpm cache, pull unneeded tools). - Add `#32`–`#36` to the backlog. Co-Authored-By: Claude Opus 4.8 --- AUDIT.md | 17 ++++++++++++++--- docs/{ => site}/index.md | 3 --- 2 files changed, 14 insertions(+), 6 deletions(-) rename docs/{ => site}/index.md (96%) diff --git a/AUDIT.md b/AUDIT.md index 41ae4fd..abefc57 100644 --- a/AUDIT.md +++ b/AUDIT.md @@ -1,4 +1,4 @@ -🔍 Audit OmniBot +# 🔍 Audit OmniBot > Les items portent un ID stable `**#N**` (référencé par les commits, ex. > « fixed in #26 »). Ils sont en **puces** à dessein : oxfmt renumérote les listes @@ -79,9 +79,15 @@ - **#26** — Permission des interactions — défaut _fail-open_ (dette de conception, faible). Le flag `requiresAdmin?: boolean` sur `InteractionHandler` (enforcé par le dispatcher) est **optionnel** : un handler sans flag est public. Sûr aujourd'hui (tous les handlers sont admin et explicitement marqués), mais repose sur l'humain pour ne pas oublier `requiresAdmin: true` sur un futur handler sensible. - **Évolution possible (option C, safe-by-construction)** : remplacer le flag optionnel par un champ **requis** type `access: "admin" | "everyone"` (aucun défaut) → le typage force chaque handler à déclarer son niveau d'accès, impossible d'oublier. - **Déclencheur** : à faire quand le nombre de handlers grandit, ou dès l'apparition du premier handler volontairement non-admin (le risque d'oubli devient alors réel). -- **#28** — CI : remplacer le grep de version Node par `jdx/mise-action`. `ci.yml` fait `pnpm/action-setup` + `grep '^node = ' .mise.toml` + `setup-node` ; maintenant que `.mise.toml` est la source de vérité (node + pnpm + pitchfork), `mise install` via l'action officielle ferait tout en une étape, sans grep fragile. (Caveat : installerait aussi pitchfork en CI — bénin.) +- **#28** — ~~CI : remplacer le grep de version Node par `jdx/mise-action`~~ 🚫 _non retenu (décidé)_. L'idée : `mise install` en une étape à la place de `pnpm/action-setup` + `grep '^node = ' .mise.toml` + `setup-node`. **Raisons du refus** : (1) perte du cache pnpm automatique fourni par `setup-node` (`cache: pnpm`) — il faudrait le re-câbler à la main (cf. #32) ; (2) `mise install` installerait aussi des outils inutiles en CI (pitchfork…) ; (3) le grep actuel, bien que peu élégant, est explicite et fonctionne. Le ratio bénéfice/inconvénient n'est pas favorable. (`docs.yml` garde `mise-action` car le build docs est peu fréquent et non sensible à ces points.) - **#29** — Branch protection `master` avec `lint` + `build` en _required status checks_ (réglage GitHub, hors repo). Prérequis pour que l'auto-merge Renovate (`platformAutomerge`) attende réellement la CI ; sans ça il pourrait fusionner sans gate. - **#30** — `pnpm dev` ne fait pas de hot-reload alors que `CLAUDE.md` annonce « tsx watch » : le script est `node --import tsx src/index.ts` (sans `watch`). À réconcilier (passer le script en `tsx watch`, ou corriger la doc). +- **#31** — Docs VitePress : logo manquant. Le hero de `docs/site/index.md` référençait `/logo.svg`, absent de `docs/site/public/` (image 404 sur le site publié). La référence `image:` a été retirée temporairement. À rétablir une fois qu'un logo existe : ajouter `docs/site/public/logo.svg` puis remettre le bloc `image: { src: /logo.svg, alt: OmniBot }` dans le frontmatter du hero. +- **#32** — CI docs : pas de cache du store pnpm. `docs.yml` utilise `jdx/mise-action` (qui ne cache que les outils, pas le store pnpm), contrairement à `ci.yml` qui bénéficie de `cache: pnpm` via `setup-node`. Le workflow ne tournant que sur changements de `docs/`, le ROI est faible — délayé. À traiter si le build docs devient lent : ajouter un `actions/cache` sur `pnpm store path` (clé sur `hashFiles('pnpm-lock.yaml')`), ou activer le cache pnpm de `mise-action`. +- **#33** — Docs VitePress : la home racine `docs/site/index.md` est entièrement en français (hero + features) alors que des index dédiés `fr/` et `en/` existent. Les boutons d'action couvrent déjà le choix de langue, donc impact faible. À neutraliser/bilinguiser si souhaité. +- **#34** — CI : `permissions: contents: read` est répété à l'identique dans les jobs `lint` et `build` de `ci.yml`. Pourrait remonter au niveau workflow (top-level) pour éviter la duplication. Cosmétique / moindre privilège. +- **#35** — CI (_incertain_) : le bloc de setup (checkout + `pnpm/action-setup` + lecture version Node + `setup-node`) est dupliqué à l'identique entre `lint` et `build`. Factorisation possible **via ancres YAML** (privilégié), mais les ancres ne savent pas concaténer une séquence de steps + des steps supplémentaires ; l'alternative propre est une **composite action** `.github/actions/setup` — dont la complexité induite reste à valider pour seulement 2 jobs. +- **#36** — CI (_incertain_) : incohérence d'install entre `lint` (`pnpm ci`) et `build` (`pnpm install --frozen-lockfile`). Uniformiser, mais **vérifié** : sans filtre, `pnpm ci` comme `pnpm install` font un (clean-)install de **tout le workspace**, vitepress (dép. d'`omnibot-docs`) compris — inutile pour linter/builder/tester le bot. Le vrai gain serait de **scoper l'install CI au paquet du bot** (filtre excluant `docs/site`) plutôt que de choisir `ci` vs `install`. `pnpm ci` n'aide pas sur ce point (il ignore `--filter`, cf. essais docs). --- @@ -105,6 +111,11 @@ Récapitulatif des actions restantes | 🔵 | Extraire client/modules dans un context.ts (#14) — délayé | | 🟣 | Accès interactions : champ requis (option C, #26) — évol. | | 🟠 | Enum >25 options : warn + doc (#27) | -| 🟣 | CI : `jdx/mise-action` au lieu du grep (#28) | | 🔵 | Branch protection : `lint`+`build` required (#29) — GitHub | | 🟣 | `pnpm dev` : hot-reload vs doc (#30) | +| 🟢 | Docs : ajouter un logo + rétablir le hero image (#31) | +| 🟢 | CI docs : cache du store pnpm (#32) — délayé | +| 🟢 | Docs : home racine FR-only vs index fr/en (#33) | +| 🟢 | CI : `permissions` au niveau workflow (#34) | +| 🟢 | CI : factoriser le setup dupliqué (#35) — incertain | +| 🟢 | CI : uniformiser/scoper l'install (#36) — incertain | diff --git a/docs/index.md b/docs/site/index.md similarity index 96% rename from docs/index.md rename to docs/site/index.md index 991603a..c70b88f 100644 --- a/docs/index.md +++ b/docs/site/index.md @@ -5,9 +5,6 @@ hero: name: OmniBot text: Bot Discord modulaire tagline: Un bot Discord modulaire, extensible et configurable. - image: - src: /logo.svg - alt: OmniBot actions: - theme: brand text: Documentation From d6296e03e0a88b0ffb05f39b5a2a280d1d7ee0f0 Mon Sep 17 00:00:00 2001 From: Antoine James Tournepiche Date: Sun, 14 Jun 2026 16:11:30 +0200 Subject: [PATCH 14/14] fix(docs): normalize DOCS_BASE and scope locale nav links - Normalize `DOCS_BASE` to always start and end with a slash so an override like `/OmniBot` (no trailing slash) doesn't break VitePress routing/assets. - Point the locale nav home links at `/fr/` and `/en/` instead of the shared root `/`, keeping each locale self-contained. Update `#33`. Co-Authored-By: Claude Opus 4.8 --- AUDIT.md | 4 ++-- docs/site/.vitepress/config.ts | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AUDIT.md b/AUDIT.md index abefc57..e6827ba 100644 --- a/AUDIT.md +++ b/AUDIT.md @@ -84,7 +84,7 @@ - **#30** — `pnpm dev` ne fait pas de hot-reload alors que `CLAUDE.md` annonce « tsx watch » : le script est `node --import tsx src/index.ts` (sans `watch`). À réconcilier (passer le script en `tsx watch`, ou corriger la doc). - **#31** — Docs VitePress : logo manquant. Le hero de `docs/site/index.md` référençait `/logo.svg`, absent de `docs/site/public/` (image 404 sur le site publié). La référence `image:` a été retirée temporairement. À rétablir une fois qu'un logo existe : ajouter `docs/site/public/logo.svg` puis remettre le bloc `image: { src: /logo.svg, alt: OmniBot }` dans le frontmatter du hero. - **#32** — CI docs : pas de cache du store pnpm. `docs.yml` utilise `jdx/mise-action` (qui ne cache que les outils, pas le store pnpm), contrairement à `ci.yml` qui bénéficie de `cache: pnpm` via `setup-node`. Le workflow ne tournant que sur changements de `docs/`, le ROI est faible — délayé. À traiter si le build docs devient lent : ajouter un `actions/cache` sur `pnpm store path` (clé sur `hashFiles('pnpm-lock.yaml')`), ou activer le cache pnpm de `mise-action`. -- **#33** — Docs VitePress : la home racine `docs/site/index.md` est entièrement en français (hero + features) alors que des index dédiés `fr/` et `en/` existent. Les boutons d'action couvrent déjà le choix de langue, donc impact faible. À neutraliser/bilinguiser si souhaité. +- **#33** — Docs VitePress : la home racine `docs/site/index.md` est entièrement en français (hero + features). **Décidé** : chaque locale est autonome — la nav `Accueil`/`Home` pointe désormais vers `/fr/` et `/en/` (et plus vers `/`), donc la racine `/` n'est plus qu'un point d'entrée rarement visité. Priorité **rétrogradée** : la bilinguiser/neutraliser devient optionnel ; alternative possible : la réduire à une simple redirection vers la locale par défaut. - **#34** — CI : `permissions: contents: read` est répété à l'identique dans les jobs `lint` et `build` de `ci.yml`. Pourrait remonter au niveau workflow (top-level) pour éviter la duplication. Cosmétique / moindre privilège. - **#35** — CI (_incertain_) : le bloc de setup (checkout + `pnpm/action-setup` + lecture version Node + `setup-node`) est dupliqué à l'identique entre `lint` et `build`. Factorisation possible **via ancres YAML** (privilégié), mais les ancres ne savent pas concaténer une séquence de steps + des steps supplémentaires ; l'alternative propre est une **composite action** `.github/actions/setup` — dont la complexité induite reste à valider pour seulement 2 jobs. - **#36** — CI (_incertain_) : incohérence d'install entre `lint` (`pnpm ci`) et `build` (`pnpm install --frozen-lockfile`). Uniformiser, mais **vérifié** : sans filtre, `pnpm ci` comme `pnpm install` font un (clean-)install de **tout le workspace**, vitepress (dép. d'`omnibot-docs`) compris — inutile pour linter/builder/tester le bot. Le vrai gain serait de **scoper l'install CI au paquet du bot** (filtre excluant `docs/site`) plutôt que de choisir `ci` vs `install`. `pnpm ci` n'aide pas sur ce point (il ignore `--filter`, cf. essais docs). @@ -115,7 +115,7 @@ Récapitulatif des actions restantes | 🟣 | `pnpm dev` : hot-reload vs doc (#30) | | 🟢 | Docs : ajouter un logo + rétablir le hero image (#31) | | 🟢 | CI docs : cache du store pnpm (#32) — délayé | -| 🟢 | Docs : home racine FR-only vs index fr/en (#33) | +| 🟢 | Docs : home racine FR-only (#33) — optionnel | | 🟢 | CI : `permissions` au niveau workflow (#34) | | 🟢 | CI : factoriser le setup dupliqué (#35) — incertain | | 🟢 | CI : uniformiser/scoper l'install (#36) — incertain | diff --git a/docs/site/.vitepress/config.ts b/docs/site/.vitepress/config.ts index f4515dc..d7be5d8 100644 --- a/docs/site/.vitepress/config.ts +++ b/docs/site/.vitepress/config.ts @@ -1,6 +1,10 @@ import { defineConfig } from "vitepress"; -const base = process.env["DOCS_BASE"] ?? "/OmniBot/"; +// VitePress requires `base` to start and end with a slash; normalize whatever +// DOCS_BASE provides so an override like `/OmniBot` doesn't break routing/assets. +const rawBase = process.env["DOCS_BASE"] ?? "/OmniBot/"; +const trimmed = rawBase.replace(/^\/+|\/+$/g, ""); +const base = trimmed ? `/${trimmed}/` : "/"; export default defineConfig({ base, @@ -27,7 +31,7 @@ export default defineConfig({ description: "Documentation du bot Discord modulaire OmniBot", themeConfig: { nav: [ - { text: "Accueil", link: "/" }, + { text: "Accueil", link: "/fr/" }, { text: "Guide", link: "/fr/guide/getting-started" }, ], sidebar: { @@ -73,7 +77,7 @@ export default defineConfig({ themeConfig: { nav: [ { text: "Guide", link: "/en/guide/getting-started" }, - { text: "Home", link: "/" }, + { text: "Home", link: "/en/" }, ], sidebar: { "/en/guide/": [