@ix-xs/metamob.api 2.0.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
- <img align=right src="https://metamob.fr/img/otomai.png">
2
- <h1><img src="https://metamob.fr/img/logo.png">Metamob</h1>
3
- <h3>Gérez vos monstres de l'Eternelle Moisson sur Dofus !</h3>
4
- <a href="https://metamob.fr/connexion">Connectez-vous</a> ou <a href="https://metamob.fr/inscription">Inscrivez-vous</a> pour profiter des avantages du site :
5
- <ul>
6
- <li>Suivez votre avancement dans la quête</li>
7
- <li>Gérez finement vos monstres</li>
8
- <li>Visualisez votre profil</li>
9
- <li>Echangez avec d'autres joueurs</li>
10
- <li>Une question ? Regardez <a href="https://metamob.fr/aide">l'aide</a></li>
11
- </ul>
1
+ # ![Metamob](https://beta.metamob.fr/img/pierre_dame_small.png) [Metamob](https://beta.metamob.fr)
2
+
3
+ <img align=right src="https://beta.metamob.fr/img/ocre.png">
4
+ <div>
5
+ <div>
6
+ <h3>Complétez votre quête du Dofus Ocre</h3>
7
+ <p>Suivez votre progression dans la quête de l'Ocre, gérez votre inventaire de monstres et échangez avec la communauté pour compléter votre collection.</p>
8
+ <p>Compatible avec Dofus Unity, Dofus Retro et Dofus Touch</p>
9
+ </div>
10
+ </div>
11
+
12
12
  <br>
13
13
  <br>
14
14
 
15
- # 🔥 @ix-xs/metamob.api
15
+ # @ix-xs/metamob.api
16
16
 
17
17
  <div align="center">
18
18
 
@@ -21,252 +21,1242 @@
21
21
  ![NPM](https://img.shields.io/badge/NPM-%23CB3837.svg?style=for-the-badge&logo=npm&logoColor=white)
22
22
  ![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)
23
23
 
24
- **🚀 SDK JavaScript officieux pour l'API Metamob - Dofus 🐉**
25
-
26
- *Une librairie performante pour interagir avec l'écosystème Dofus via Metamob*
27
-
28
24
  [![npm version](https://badge.fury.io/js/%40ix-xs%2Fmetamob.api.svg)](https://www.npmjs.com/package/@ix-xs/metamob.api)
29
25
  [![Downloads](https://img.shields.io/npm/dm/@ix-xs/metamob.api.svg)](https://www.npmjs.com/package/@ix-xs/metamob.api)
30
26
  [![License](https://img.shields.io/npm/l/@ix-xs/metamob.api.svg)](https://github.com/ix-xs/metamob.api/blob/main/LICENSE)
31
27
 
32
28
  </div>
29
+ <br>
33
30
 
34
- ---
31
+ ## 📖 Table des matières
35
32
 
36
- ## 🌟 Aperçu
33
+ - [✨ Présentation](#-présentation)
34
+ - [🚀 Installation](#-installation)
35
+ - [🔐 Authentification](#-authentification)
36
+ - [⚙️ Limites de l'API](#️-limites-de-lapi)
37
+ - [📦 Structure des réponses](#-structure-des-réponses)
38
+ - [💾 Cache de données](#-cache-de-données)
39
+ - [📚 Documentation API](#-documentation-api)
40
+ - [Versions du jeu](#versions-du-jeu)
41
+ - [Serveurs](#serveurs)
42
+ - [Types de monstres](#types-de-monstres)
43
+ - [Modèles de quête](#modèles-de-quête)
44
+ - [Recherche d'utilisateurs](#recherche-dutilisateurs)
45
+ - [Profils utilisateurs](#profils-utilisateurs)
46
+ - [Quêtes utilisateurs](#quêtes-utilisateurs)
47
+ - [Détails d'une quête utilisateur](#détails-dune-quête-utilisateur)
48
+ - [Partenaires d'échange](#partenaires-déchange)
49
+ - [Modifier les paramètres d'une quête utilisateur](#modifier-les-paramètres-dune-quête-utilisateur)
50
+ - [Modifier plusieurs monstres d'une quête utilisateur](#modifier-plusieurs-monstres-dune-quête-utilisateur)
51
+ - [Paramètres de trade manuels d'une quête utilisateur](#paramètres-de-trade-manuels-dune-quête-utilisateur)
37
52
 
38
- **@ix-xs/metamob.api** est un SDK JavaScript moderne et puissant conçu spécialement pour l'API Metamob, permettant aux développeurs de créer facilement des applications Dofus avec une intégration fluide et performante.
53
+ ## Présentation
39
54
 
40
- ### Fonctionnalités principales
55
+ **@ix-xs/metamob.api** est un client Node.js complet pour accéder programmatiquement à l'[API Metamob](https://beta.metamob.fr/help/api). Metamob est une plateforme communautaire dédiée au **suivi de la quête de l'Ocre** dans l'univers Dofus, permettant aux joueurs de gérer leur inventaire de monstres et d'échanger avec d'autres collectionneurs.
41
56
 
42
- - 🔥 **Cache intelligent** avec synchronisation automatique disque/mémoire
43
- - ⚡ **Performances optimales** grâce à un système de cache avancé
44
- - 🛡️ **Sécurité renforcée** avec écriture atomique des fichiers
45
- - 🎯 **API moderne** avec support complet TypeScript (jsdoc)
46
- - 📖 **Documentation complète** avec exemples pratiques
47
- - 🔄 **Rate limiting** automatique avec retry intelligent
48
- - 🌐 **Support complet** de toutes les endpoints Metamob
57
+ ### 🎮 Compatible avec
49
58
 
50
- ---
59
+ - **Dofus Unity** - Version moderne du jeu
60
+ - **Dofus Retro (1.29)** - Version rétro/classique
61
+ - **Dofus Touch** - Version mobile
62
+
63
+ ### 🎯 Cas d'usage
64
+
65
+ - 📊 **Bots Discord** - Créer des commandes pour consulter les données Metamob
66
+ - 🔧 **Outils personnalisés** - Développer des applications pour gérer votre progression
67
+ - 📈 **Intégrations** - Combiner Metamob avec d'autres services (webhooks, monitoring, etc.)
51
68
 
52
- ## 🚀 Installation rapide
69
+ ## 🚀 Installation
70
+
71
+ ### NPM
53
72
 
54
73
  ```bash
55
- # NPM
56
74
  npm install @ix-xs/metamob.api
75
+ ```
76
+
77
+ ## 🔐 Authentification
78
+
79
+ ### Créer une clé API
80
+
81
+ 1. ✅ Connectez-vous à votre compte sur [Metamob](https://beta.metamob.fr)
82
+ 2. ⚙️ Accédez à vos **Paramètres**
83
+ 3. 🔑 Naviguez vers la section **Clé API**
84
+ 4. ✨ Cliquez sur **Générer une clé**
85
+ 5. 📋 **Copiez** votre clé (elle ne sera plus affichée après cette étape)
86
+
87
+ ## ⚙️ Limites de l'API
88
+
89
+ L'API Metamob applique des **rate limits** pour garantir la stabilité du service :
90
+
91
+ ### Rate Limiting
92
+
93
+ | Limite | Valeur |
94
+ | ----------------------- | ------------------------ |
95
+ | **Requêtes par minute** | 60 par clé API |
96
+ | **Code de dépassement** | `429 Too Many Requests` |
97
+ | **En-tête de retry** | `Retry-After` (secondes) |
98
+
99
+ ## 📦 Structure des réponses
100
+
101
+ Toutes les requêtes retournent un objet JSON **normalisé** avec une structure cohérente :
102
+
103
+ ### Format standard
104
+
105
+ ```javascript
106
+ {
107
+ ok: boolean, // Indique le succès de la requête
108
+ status: number, // Code HTTP (200, 404, 429, 500, etc.)
109
+ statusText: string, // Libellé HTTP ("OK", "Not Found", etc.)
110
+ data?: Object|Object[], // Données retournées (absent si ok = false)
111
+ pagination?: { // Présent uniquement pour les listes paginées
112
+ total: number, // Nombre total d'éléments
113
+ limit: number, // Nombre d'éléments par page
114
+ offset: number, // Index du premier élément
115
+ },
116
+ error?: string, // Message d'erreur (si ok = false)
117
+ retryAfter?: number, // Délai avant nouvelle tentative (si status = 429)
118
+ }
119
+ ```
120
+
121
+ ### Exemple : succès
122
+
123
+ ```javascript
124
+ {
125
+ ok: true,
126
+ status: 200,
127
+ statusText: "OK",
128
+ data: [
129
+ { id: 1, name: "Brial", community: "France", ... },
130
+ { id: 2, name: "Rafal", community: "France", ... },
131
+ ],
132
+ pagination: {
133
+ total: 20,
134
+ limit: 20,
135
+ offset: 0
136
+ }
137
+ }
138
+ ```
57
139
 
58
- # Yarn
59
- yarn add @ix-xs/metamob.api
140
+ ### Exemple : erreur
60
141
 
61
- # PNPM
62
- pnpm add @ix-xs/metamob.api
142
+ ```javascript
143
+ {
144
+ ok: false,
145
+ status: 404,
146
+ statusText: "Not Found",
147
+ error: "Utilisateur 'xyz' non trouvé"
148
+ }
63
149
  ```
64
150
 
65
- ### 📋 Prérequis
151
+ ### Exemple : rate limit
152
+
153
+ ```javascript
154
+ {
155
+ ok: false,
156
+ status: 429,
157
+ statusText: "Too Many Requests",
158
+ retryAfter: 45,
159
+ error: "Trop de requêtes. Veuillez réessayer après 45 secondes"
160
+ }
161
+ ```
162
+
163
+ ## 💾 Cache de données
164
+
165
+ ### 🎯 Concept
166
+
167
+ Ce package intègre un **cache de données statiques** embarqué sous forme de fichiers JSON. Ces données correspondent à des informations quasi-permanentes côté Metamob (serveurs, types de monstres, catalogues, etc.).
168
+
169
+ ### ✅ Avantages du cache
170
+
171
+ | Avantage | Description |
172
+ | -------------------------- | ------------------------------------------------------------ |
173
+ | **🚀 Performance** | Pas de requête API pour les données statiques |
174
+ | **📉 Réduction API** | Économise vos appels API pour les vraies données |
175
+ | **🎯 Recherche intuitive** | Rechercher par nom au lieu de chercher par ID |
176
+ | **↔️ Conversion** | Convertir facilement ID ↔ Nom |
177
+ | **⚡ Offline** | Données disponibles même sans réseau (après première charge) |
178
+
179
+ ### 📊 Données en cache
66
180
 
67
- - **Node.js** >= 18.0.0
68
- - **NPM** >= 8.0.0
69
- - Une clé API Metamob valide
181
+ | Clé | Contenu | Utilité |
182
+ | -------------- | ----------------------------------------------- | ----------------------------------- |
183
+ | `gameVersions` | Versions du jeu (Unity, Retro, Touch) | Identifier les versions disponibles |
184
+ | `servers` | Liste des serveurs par communauté | Chercher un serveur par nom |
185
+ | `monsterTypes` | Types de monstres (monstre, archimonstre, boss) | Filtrer par type |
186
+ | `monsters` | Catalogue complet des monstres multilingues | Rechercher un monstre par nom |
187
+
188
+ ### 🔍 Utilisation du cache
189
+
190
+ ```javascript
191
+ // Au lieu de faire :
192
+ client.getMonsters(); // requête GET /monsters -> paginé
193
+
194
+ // Vous pouvez faire :
195
+ client.cache.monsters; // cache, complet
196
+ ```
197
+
198
+ ### 🔄 Mise à jour du cache
199
+
200
+ Le cache n'est **pas mis à jour automatiquement** depuis l'API en temps réel. Les mises à jour sont gérées via de **nouvelles versions du package** NPM.
201
+
202
+ **Pour obtenir les dernières données :**
203
+
204
+ ```bash
205
+ npm update @ix-xs/metamob.api
206
+ ```
207
+
208
+ Les données en cache reflètent les informations les plus récentes de Metamob à chaque nouvelle version du package.
209
+
210
+ ### ⚠️ Limitations
211
+
212
+ - Le cache est **read-only** (lecture seule)
213
+ - Les données statiques changent rarement, mais peuvent être obsolètes entre versions
214
+ - Pour les données **dynamiques** (profils, quêtes), utiliser les endpoints API appropriés
215
+
216
+ ## 📚 Documentation API
217
+
218
+ ### Initialisation
219
+
220
+ ```javascript
221
+ const MetamobAPI = require("@ix-xs/metamob.api");
222
+ const client = new MetamobAPI(process.env.METAMOB_API_KEY);
223
+ ```
70
224
 
71
225
  ---
72
226
 
73
- ## 💡 Utilisation de base
227
+ ### Versions du jeu
228
+
229
+ Récupérer la liste des versions du jeu disponibles sur Metamob.
230
+
231
+ #### Signature
74
232
 
75
233
  ```javascript
76
- const metamobAPI = require("@ix-xs/metamob.api");
77
- const client = new metamobAPI("VOTRE_CLÉ_API_METAMOB");
234
+ getGameVersions(options?: { game_name?: string })
235
+ ```
78
236
 
79
- // Utilisation du cache (recommandé)
80
- console.log(client.cache.servers); // Serveurs en cache
81
- console.log(client.cache.monsters); // Monstres en cache
82
- console.log(client.cache.areas); // Zones en cache
237
+ #### Types
83
238
 
84
- // Ou récupération via API
85
- const servers = await client.getServers();
86
- const user = await client.getUser("Ix-xs");
87
- const monsters = await client.getUserMonsters("Ix-xs");
239
+ ```javascript
240
+ /**
241
+ * @typedef {object} GameVersion
242
+ * @property {number} id - Identifiant unique
243
+ * @property {string} name - Nom de la version ("Dofus (Unity)", "Dofus Retro (1.29)", "Dofus Touch")
244
+ */
245
+ ```
246
+
247
+ #### Exemples
248
+
249
+ **Lister toutes les versions**
250
+
251
+ ```javascript
252
+ const response = await client.getGameVersions();
253
+
254
+ if (!response.ok) {
255
+ return console.error(response.error ?? response.statusText);
256
+ }
257
+
258
+ response.data.forEach((version) => {
259
+ console.log(`${version.id}: ${version.name}`);
260
+ });
261
+ // Output:
262
+ // 1: Dofus (Unity)
263
+ // 2: Dofus Retro (1.29)
264
+ // 3: Dofus Touch
265
+ ```
266
+
267
+ **Récupérer une version spécifique**
268
+
269
+ ```javascript
270
+ const response = await client.getGameVersions({
271
+ game_name: "Dofus (Unity)",
272
+ });
273
+
274
+ if (response.ok) {
275
+ console.log(response.data);
276
+ // { id: 1, name: "Dofus (Unity)" }
277
+ }
88
278
  ```
89
279
 
90
280
  ---
91
281
 
92
- ## 🏗️ Architecture du cache
282
+ ### Serveurs
93
283
 
94
- ### 🧠 Cache intelligent multicouche
284
+ Récupérer la liste des serveurs de jeu disponibles.
95
285
 
96
- Notre système de cache combine :
286
+ #### Signature
97
287
 
98
- - **📁 Cache disque** : Persistance des données via JSON
99
- - **💾 Cache mémoire** : Accès ultra-rapide via `require()`
100
- - **🔄 Synchronisation automatique** : Mise à jour seamless
101
- - **🛡️ Écriture atomique** : Prévention de la corruption des données
288
+ ```javascript
289
+ getServers(options?: { server_name?: string })
290
+ ```
291
+
292
+ #### Types
102
293
 
103
294
  ```javascript
104
- // Le cache est automatiquement synchronisé
105
- await client.getServers(); // Met à jour le cache si nécessaire
295
+ /**
296
+ * @typedef {object} Server
297
+ * @property {number} id - Identifiant unique
298
+ * @property {string} name - Nom du serveur
299
+ * @property {string} community - Communauté ("World" ou "France")
300
+ * @property {GameVersion} game_version - Version du jeu du serveur
301
+ */
302
+ ```
106
303
 
107
- // Accès instantané depuis le cache mémoire
108
- const servers = client.cache.servers;
304
+ #### Serveurs disponibles
305
+
306
+ | France | World |
307
+ | ---------- | ---------- |
308
+ | Brial | Brial |
309
+ | Rafal | Rafal |
310
+ | Salar | Salar |
311
+ | Kourial | Kourial |
312
+ | Dakal | Dakal |
313
+ | Mikhal | Mikhal |
314
+ | Imagiro | Imagiro |
315
+ | Hell Mina | Hell Mina |
316
+ | Tylezia | Tylezia |
317
+ | Orukam | Orukam |
318
+ | Tal Kasha | Tal Kasha |
319
+ | Draconiros | Draconiros |
320
+ | Ombre | Ombre |
321
+ | Fallanster | Fallanster |
322
+ | Boune | Boune |
323
+ | Allisteria | Allisteria |
324
+ | Blair | Blair |
325
+ | Kelerog | Kelerog |
326
+ | Talok | Talok |
327
+ | Tiliwan | Tiliwan |
328
+
329
+ #### Exemples
330
+
331
+ **Lister tous les serveurs**
332
+
333
+ ```javascript
334
+ const response = await client.getServers();
335
+
336
+ if (response.ok) {
337
+ response.data.forEach((server) => {
338
+ console.log(
339
+ `${server.name} (${server.community}) - ${server.game_version.name}`,
340
+ );
341
+ });
342
+ }
343
+ ```
344
+
345
+ **Récupérer un serveur spécifique**
346
+
347
+ ```javascript
348
+ const response = await client.getServers({
349
+ server_name: "Brial",
350
+ });
351
+
352
+ if (response.ok) {
353
+ console.log(response.data);
354
+ // {
355
+ // id: 1,
356
+ // name: "Brial",
357
+ // community: "France",
358
+ // game_version: { id: 1, name: "Dofus (Unity)" }
359
+ // }
360
+ }
109
361
  ```
110
362
 
111
- ### 📊 Types de cache disponibles
363
+ **Grouper par communauté**
112
364
 
113
- | Type | Description | Endpoint |
114
- |------|-------------|----------|
115
- | `servers` | Serveurs Dofus | `/serveurs` |
116
- | `monsters` | Base de données des monstres | `/monstres` |
117
- | `areas` | Zones de jeu | `/zones` |
118
- | `subareas` | Sous-zones détaillées | `/sous-zones` |
365
+ ```javascript
366
+ const response = await client.getServers();
367
+
368
+ if (response.ok) {
369
+ const byRegion = response.data.reduce((acc, server) => {
370
+ if (!acc[server.community]) acc[server.community] = [];
371
+ acc[server.community].push(server.name);
372
+ return acc;
373
+ }, {});
374
+
375
+ console.log(byRegion);
376
+ // {
377
+ // France: ["Brial", "Rafal", ...],
378
+ // World: ["Brial", "Rafal", ...]
379
+ // }
380
+ }
381
+ ```
119
382
 
120
383
  ---
121
384
 
122
- ## 🔧 API complète
385
+ ### Types de monstres
386
+
387
+ Récupérer les catégories de monstres.
123
388
 
124
- ### 👤 Gestion des utilisateurs
389
+ #### Signature
125
390
 
126
391
  ```javascript
127
- // Informations utilisateur
128
- const user = await client.getUser("pseudo");
392
+ getMonsterTypes(options?: { type_name?: string })
393
+ ```
394
+
395
+ #### Types
396
+
397
+ ```javascript
398
+ /**
399
+ * @typedef {object} MonsterType
400
+ * @property {number} id - Identifiant unique
401
+ * @property {object} name - Nom multilingue
402
+ * @property {string} name.fr - Nom en français
403
+ * @property {string} name.en - Nom en anglais
404
+ * @property {string} name.es - Nom en espagnol
405
+ */
406
+ ```
407
+
408
+ #### Types disponibles
129
409
 
130
- // Monstres d'un utilisateur
131
- const userMonsters = await client.getUserMonsters("pseudo");
410
+ | Français | Anglais | Espagnol |
411
+ | ------------ | ----------- | ------------- |
412
+ | Monstre | Monster | Monstruo |
413
+ | Archimonstre | Archmonster | Archimonstruo |
414
+ | Boss | Boss | Boss |
132
415
 
133
- // Mise à jour des monstres
134
- await client.setUserMonsters("pseudo", "unique_id", [
135
- { monstre: "Arakne", etat: "recherche", quantite: 5 },
136
- { monstre: "Boufton Blanc", etat: "propose", quantite: 2 }
137
- ]);
416
+ #### Exemples
138
417
 
139
- // Réinitialisation des monstres
140
- await client.resetUserMonsters("pseudo", "unique_id");
418
+ **Lister tous les types**
419
+
420
+ ```javascript
421
+ const response = await client.getMonsterTypes();
422
+
423
+ if (response.ok) {
424
+ response.data.forEach((type) => {
425
+ console.log(
426
+ `FR: ${type.name.fr}, EN: ${type.name.en}, ES: ${type.name.es}`,
427
+ );
428
+ });
429
+ }
141
430
  ```
142
431
 
143
- ### 🎮 Données de jeu
432
+ **Récupérer un type spécifique**
144
433
 
145
434
  ```javascript
146
- // Cache instantané (recommandé)
147
- const servers = client.cache.servers;
148
- const monsters = client.cache.monsters;
149
- const areas = client.cache.areas;
150
- const subareas = client.cache.subareas;
435
+ const response = await client.getMonsterTypes({
436
+ type_name: "boss",
437
+ });
151
438
 
152
- // Ou via API avec mise à jour du cache
153
- const freshServers = await client.getServers();
154
- const freshMonsters = await client.getMonsters();
155
- const freshAreas = await client.getAreas();
156
- const freshSubareas = await client.getSubareas();
439
+ if (response.ok) {
440
+ console.log(response.data);
441
+ // {
442
+ // id: 3,
443
+ // name: { fr: "Boss", en: "Boss", es: "Boss" }
444
+ // }
445
+ }
157
446
  ```
158
447
 
159
- ### 🐙 Kralamoures
448
+ ---
449
+
450
+ ### Modèles de quête
451
+
452
+ Récupérer les modèles de quête avec la liste des monstres à capturer par étape.
453
+
454
+ #### Signature
455
+
456
+ ```javascript
457
+ getQuestTemplates(options?: {
458
+ game_name?: string,
459
+ step?: number,
460
+ limit?: number,
461
+ offset?: number
462
+ })
463
+ ```
464
+
465
+ #### Types
466
+
467
+ ```javascript
468
+ /**
469
+ * @typedef {object} QuestTemplate
470
+ * @property {number} id - Identifiant
471
+ * @property {GameVersion} game_version - Version du jeu
472
+ * @property {number} monster_count - Nombre total de monstres
473
+ * @property {number} step_count - Nombre d'étapes
474
+ *
475
+ * @typedef {object} QuestTemplateDetail
476
+ * @property {number} id - Identifiant
477
+ * @property {GameVersion} game_version - Version du jeu
478
+ * @property {Array} monsters - Monstres avec leur étape
479
+ * @property {Pagination} pagination - Infos de pagination
480
+ */
481
+ ```
482
+
483
+ #### Exemples
484
+
485
+ **Lister les modèles de quête**
160
486
 
161
487
  ```javascript
162
- // Toutes les ouvertures kralamoures
163
- const kralamoures = await client.getKralamoures();
488
+ const response = await client.getQuestTemplates();
489
+
490
+ if (response.ok) {
491
+ console.log(`Modèles trouvés: ${response.pagination.total}`);
492
+ response.data.forEach((template) => {
493
+ console.log(
494
+ `${template.game_version.name}: ${template.monster_count} monstres en ${template.step_count} étapes`,
495
+ );
496
+ });
497
+ }
498
+ ```
499
+
500
+ **Récupérer les monstres d'une étape spécifique**
501
+
502
+ ```javascript
503
+ const response = await client.getQuestTemplates({
504
+ game_name: "Dofus (Unity)",
505
+ step: 1,
506
+ limit: 50,
507
+ });
508
+
509
+ if (response.ok) {
510
+ console.log(`Étape 1 - Monstres à capturer:`);
511
+ response.data.monsters.forEach((monster) => {
512
+ console.log(`- ${monster.name.fr} (étape ${monster.step})`);
513
+ });
514
+ }
515
+ ```
164
516
 
165
- // Avec filtres
166
- const filtered = await client.getKralamoures({
167
- server: "Salar",
168
- start_date: "2025-01-01",
169
- end_date: "2025-12-31"
517
+ **Pagination**
518
+
519
+ ```javascript
520
+ const response = await client.getQuestTemplates({
521
+ game_name: "Dofus (Unity)",
522
+ step: 1,
523
+ limit: 10,
524
+ offset: 20, // Sauter les 20 premiers résultats
170
525
  });
526
+
527
+ if (response.ok) {
528
+ console.log(`Résultats 21-30 sur ${response.pagination.total}`);
529
+ }
171
530
  ```
172
531
 
173
532
  ---
174
533
 
175
- ### 📊 Structure de réponse
534
+ ### Recherche d'utilisateurs
535
+
536
+ Rechercher des utilisateurs ayant des quêtes publiques.
176
537
 
177
- Toutes les méthodes retournent un objet standardisé :
538
+ #### Signature
178
539
 
179
540
  ```javascript
180
- {
181
- ok: boolean, // Succès de la requête
182
- status: number, // Code de statut HTTP
183
- statusText: string, // Message de statut
184
- retryAfter?: number, // Délai avant retry (si 429)
185
- errors?: string[], // Erreurs éventuelles
186
- data?: any // Données de réponse
541
+ searchUsers(
542
+ query: string,
543
+ options?: {
544
+ server_name?: string,
545
+ active_within_days?: number,
546
+ limit?: number,
547
+ offset?: number
548
+ }
549
+ )
550
+ ```
551
+
552
+ #### Paramètres
553
+
554
+ | Paramètre | Requis | Type | Description |
555
+ | -------------------- | ------ | ------ | ------------------------------------------------------- |
556
+ | `query` | ✅ | string | Terme de recherche (min. 3 caractères) |
557
+ | `server_name` | ❌ | string | Filtrer par serveur |
558
+ | `active_within_days` | ❌ | number | Actifs dans les N derniers jours (défaut: 90, max: 365) |
559
+ | `limit` | ❌ | number | Nombre de résultats (défaut: 20, max: 50) |
560
+ | `offset` | ❌ | number | Décalage pour pagination (défaut: 0) |
561
+
562
+ #### Types
563
+
564
+ ```javascript
565
+ /**
566
+ * @typedef {object} UserAvatar
567
+ * @property {number} id - Identifiant de l'avatar
568
+ * @property {object} name - Nom multilingue
569
+ * @property {string} image - URL de l'image
570
+ *
571
+ * @typedef {object} Search
572
+ * @property {string} username - Nom d'utilisateur
573
+ * @property {UserAvatar} avatar - Avatar utilisateur
574
+ * @property {string} last_active - Dernière activité (ISO 8601)
575
+ */
576
+ ```
577
+
578
+ #### Exemples
579
+
580
+ **Recherche basique**
581
+
582
+ ```javascript
583
+ const response = await client.searchUsers("jean");
584
+
585
+ if (!response.ok) {
586
+ return console.error(response.error);
587
+ }
588
+
589
+ response.data.forEach((user) => {
590
+ console.log(`${user.username} (${user.avatar.name.fr})`);
591
+ });
592
+ ```
593
+
594
+ **Filtrer par serveur et activité**
595
+
596
+ ```javascript
597
+ const response = await client.searchUsers("jean", {
598
+ server_name: "Brial",
599
+ active_within_days: 30, // Actifs dans les 30 derniers jours
600
+ limit: 10,
601
+ });
602
+
603
+ if (response.ok) {
604
+ console.log(`${response.pagination.total} utilisateurs trouvés`);
605
+ response.data.forEach((user) => {
606
+ console.log(`- ${user.username} (dernière activité: ${user.last_active})`);
607
+ });
608
+ }
609
+ ```
610
+
611
+ **Pagination avancée**
612
+
613
+ ```javascript
614
+ async function searchAllUsers(query, pageSize = 50) {
615
+ let allResults = [];
616
+ let offset = 0;
617
+ let hasMore = true;
618
+
619
+ while (hasMore) {
620
+ const response = await client.searchUsers(query, {
621
+ limit: pageSize,
622
+ offset,
623
+ });
624
+
625
+ if (!response.ok) break;
626
+
627
+ allResults.push(...response.data);
628
+ hasMore =
629
+ response.pagination.offset + response.pagination.limit <
630
+ response.pagination.total;
631
+ offset += pageSize;
632
+ }
633
+
634
+ return allResults;
187
635
  }
188
636
  ```
189
637
 
190
638
  ---
191
639
 
192
- ## Optimisations avancées
640
+ ### Profils utilisateurs
641
+
642
+ Récupérer le profil détaillé d'un utilisateur.
643
+
644
+ #### Signature
193
645
 
194
- ### 🚀 Cache Strategy
646
+ ```javascript
647
+ getUser(username: string)
648
+ ```
649
+
650
+ #### Types
195
651
 
196
652
  ```javascript
197
- // Préférez toujours le cache pour les données statiques
198
- const servers = client.cache.servers; // ✅ Instantané
199
- const servers = await client.getServers(); // Plus lent
653
+ /**
654
+ * @typedef {object} User
655
+ * @property {string} username - Nom d'utilisateur
656
+ * @property {string} bio - Biographie de l'utilisateur
657
+ * @property {UserAvatar} avatar - Avatar utilisateur
658
+ * @property {string} created_at - Date de création du compte (ISO 8601)
659
+ * @property {string} last_active - Dernière activité (ISO 8601)
660
+ */
661
+ ```
662
+
663
+ #### Exemples
664
+
665
+ **Récupérer un profil**
200
666
 
201
- // Le cache se met à jour automatiquement si nécessaire
667
+ ```javascript
668
+ const response = await client.getUser("ix-xs");
669
+
670
+ if (!response.ok) {
671
+ return console.error(`Utilisateur non trouvé: ${response.error}`);
672
+ }
673
+
674
+ const user = response.data;
675
+ console.log(`
676
+ ${user.username}
677
+ Avatar: ${user.avatar.name.fr}
678
+ Bio: ${user.bio || "Pas de bio"}
679
+ Compte créé: ${new Date(user.created_at).toLocaleDateString("fr-FR")}
680
+ Dernière activité: ${new Date(user.last_active).toLocaleDateString("fr-FR")}
681
+ `);
202
682
  ```
203
683
 
204
- ### 🔄 Rate Limiting
684
+ **Vérifier l'activité d'un utilisateur**
205
685
 
206
- Le SDK gère automatiquement :
207
- - **Détection du rate limiting** (429)
208
- - **Retry automatique** avec backoff
209
- - **Headers de retry** respectés
686
+ ```javascript
687
+ const response = await client.getUser("jean");
688
+
689
+ if (response.ok) {
690
+ const user = response.data;
691
+ const daysSinceActive = Math.floor(
692
+ (Date.now() - new Date(user.last_active)) / (1000 * 60 * 60 * 24),
693
+ );
694
+
695
+ console.log(`${user.username} a été actif il y a ${daysSinceActive} jours`);
696
+ }
697
+ ```
210
698
 
211
699
  ---
212
700
 
213
- ## 🛠️ Configuration avancée
701
+ ### Quêtes utilisateurs
702
+
703
+ Récupérer la liste des quêtes publiques d'un utilisateur.
214
704
 
215
- ### 📁 Structure des fichiers cache
705
+ #### Signature
216
706
 
707
+ ```javascript
708
+ getUserQuests(username: string)
217
709
  ```
218
- .cache/
219
- ├── $.js # Index des caches
220
- ├── servers.json # Serveurs
221
- ├── monsters.json # Monstres
222
- ├── areas.json # Zones
223
- └── subareas.json # Sous-zones
710
+
711
+ #### Types
712
+
713
+ ```javascript
714
+ /**
715
+ * @typedef {object} Quest
716
+ * @property {string} slug - Identifiant unique de la quête
717
+ * @property {string} character_name - Nom du personnage Dofus
718
+ * @property {number} current_step - Étape actuelle de la quête
719
+ * @property {number} parallel_quests - Nombre de quêtes parallèles
720
+ * @property {number} wanted_count - Nombre de monstres recherchés
721
+ * @property {number} offered_count - Nombre de monstres proposés
722
+ * @property {Server} server - Serveur du personnage
723
+ * @property {QuestTemplate} quest_template - Modèle de quête
724
+ */
224
725
  ```
225
726
 
226
- ### 🔧 Personnalisation
727
+ #### Exemples
227
728
 
228
- Le cache utilise :
229
- - **write-file-atomic** pour l'écriture sécurisée
230
- - **Formatage JSON** avec indentation (4 espaces)
231
- - **Rechargement automatique** du cache Node.js
729
+ **Lister les quêtes d'un utilisateur**
730
+
731
+ ```javascript
732
+ const response = await client.getUserQuests("ix-xs");
733
+
734
+ if (!response.ok) {
735
+ return console.error(response.error);
736
+ }
737
+
738
+ response.data.forEach((quest) => {
739
+ console.log(`
740
+ Personnage: ${quest.character_name}
741
+ Serveur: ${quest.server.name}
742
+ Étape: ${quest.current_step}/${quest.quest_template.step_count}
743
+ Recherche: ${quest.wanted_count} / Proposé: ${quest.offered_count}
744
+ `);
745
+ });
746
+ ```
747
+
748
+ **Analyser la progression de quête**
749
+
750
+ ```javascript
751
+ const response = await client.getUserQuests("jean");
752
+
753
+ if (response.ok) {
754
+ response.data.forEach((quest) => {
755
+ const progression = Math.floor(
756
+ (quest.current_step / quest.quest_template.step_count) * 100,
757
+ );
758
+
759
+ console.log(`
760
+ ${quest.character_name}: ${progression}% complété
761
+ Étape ${quest.current_step}/${quest.quest_template.step_count}
762
+ Progression: ${"█".repeat(Math.floor(progression / 5))}${"░".repeat(20 - Math.floor(progression / 5))}
763
+ `);
764
+ });
765
+ }
766
+ ```
767
+
768
+ **Trouver des fournisseurs de monstres**
769
+
770
+ ```javascript
771
+ const response = await client.getUserQuests("jean");
772
+
773
+ if (response.ok) {
774
+ const providers = response.data.filter((quest) => quest.offered_count > 0);
775
+
776
+ console.log(
777
+ `${quest.character_name} propose ${quest.offered_count} monstres`,
778
+ );
779
+ }
780
+ ```
232
781
 
233
782
  ---
234
783
 
235
- ## 🏆 Contributeurs & Support
784
+ ### Détails d'une quête utilisateur
236
785
 
237
- <div align="center">
786
+ Récupérer les monstres d'une quête spécifique avec filtres et pagination.
787
+
788
+ #### Signature
789
+
790
+ ```javascript
791
+ getUserQuestMonsters(
792
+ username: string,
793
+ quest_slug: string,
794
+ options?: {
795
+ status?: "wanted" | "offered",
796
+ step?: number,
797
+ limit?: number,
798
+ offset?: number
799
+ }
800
+ )
801
+ ```
802
+
803
+ #### Paramètres
804
+
805
+ | Paramètre | Requis | Type | Description |
806
+ | ------------ | ------ | ------ | --------------------------------------------- |
807
+ | `username` | ✅ | string | Nom d'utilisateur |
808
+ | `quest_slug` | ✅ | string | Identifiant (slug) de la quête |
809
+ | `status` | ❌ | string | "wanted" (recherchés) ou "offered" (proposés) |
810
+ | `step` | ❌ | number | Filtrer par numéro d'étape |
811
+ | `limit` | ❌ | number | Nombre de résultats (défaut: 50, max: 200) |
812
+ | `offset` | ❌ | number | Décalage pour pagination (défaut: 0) |
813
+
814
+ #### Types
815
+
816
+ ```javascript
817
+ /**
818
+ * @typedef {Monster & { step: number, owned: number, status: number }} QuestMonster
819
+ * @property {number} step - Numéro d'étape du monstre
820
+ * @property {number} owned - Quantité possédée
821
+ * @property {number} status - Statut (0=neutre, 1=recherché, 2=proposé)
822
+ */
823
+ ```
824
+
825
+ #### Exemples
826
+
827
+ **Lister tous les monstres d'une quête**
828
+
829
+ ```javascript
830
+ const response = await client.getUserQuestMonsters("ix-xs", "abcdef");
831
+
832
+ if (response.ok) {
833
+ console.log(`${response.pagination.total} monstres dans la quête`);
834
+ response.data.forEach((monster) => {
835
+ console.log(
836
+ `${monster.name.fr} - Étape ${monster.step} - Possédé: ${monster.owned}`,
837
+ );
838
+ });
839
+ }
840
+ ```
238
841
 
239
- ### 👨‍💻 Créateur
842
+ **Filtrer par statut**
240
843
 
241
- <img src="https://cdn.discordapp.com/avatars/782307250751406091/a_3f71f1ac5e1664038fdf33c2c408482e.gif" style="border-radius:0.5rem; width:5rem; height:auto">
844
+ ```javascript
845
+ // Monstres proposés uniquement
846
+ const response = await client.getUserQuestMonsters("ix-xs", "abcdef", {
847
+ status: "offered",
848
+ });
849
+
850
+ if (response.ok) {
851
+ console.log("Monstres proposés à l'échange:");
852
+ response.data.forEach((m) => console.log(`- ${m.name.fr} (x${m.owned})`));
853
+ }
854
+ ```
855
+
856
+ **Filtrer par étape**
242
857
 
243
- **Ix-xs**
244
- *Développeur auto-didacte & Passionné Dofus*
858
+ ```javascript
859
+ // Monstres de l'étape 5
860
+ const response = await client.getUserQuestMonsters("ix-xs", "abcdef", {
861
+ step: 5,
862
+ });
245
863
 
246
- [![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discordapp.com/users/782307250751406091)
247
- [![GitHub](https://img.shields.io/badge/GitHub-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/ix-xs)
864
+ if (response.ok) {
865
+ console.log(`Monstres de l'étape 5: ${response.pagination.total}`);
866
+ }
867
+ ```
248
868
 
249
869
  ---
250
870
 
251
- ### 💬 Besoin d'aide ?
871
+ ### Partenaires d'échange
252
872
 
253
- - 🐛 **Issues** : [GitHub Issues](https://github.com/ix-xs/metamob.api/issues)
254
- - 💬 **Discord** : `Ix-xs` - Contact direct
873
+ Trouve des utilisateurs avec qui échanger des monstres en analysant les compatibilités entre quêtes.
255
874
 
256
- </div>
875
+ #### Signature
876
+
877
+ ```javascript
878
+ matchUserQuest(
879
+ user_api_key: string,
880
+ quest_slug: string,
881
+ options?: {
882
+ direction?: "they_have" | "they_want" | "both",
883
+ active_within_days?: number,
884
+ min_parallel_quests?: number,
885
+ limit?: number,
886
+ offset?: number
887
+ }
888
+ )
889
+ ```
890
+
891
+ #### Paramètres
892
+
893
+ | Paramètre | Requis | Type | Description |
894
+ | --------------------- | ------ | ------ | ------------------------------------------------------- |
895
+ | `user_api_key` | ✅ | string | Clé API de l'utilisateur |
896
+ | `quest_slug` | ✅ | string | Identifiant (slug) de la quête |
897
+ | `direction` | ❌ | string | Type de match (défaut: "both") |
898
+ | `active_within_days` | ❌ | number | Actifs dans les N derniers jours (défaut: 30, max: 365) |
899
+ | `min_parallel_quests` | ❌ | number | Nombre min de quêtes parallèles (défaut: 1, max: 20) |
900
+ | `limit` | ❌ | number | Nombre de résultats (défaut: 20, max: 50) |
901
+ | `offset` | ❌ | number | Décalage pour pagination (défaut: 0) |
902
+
903
+ #### Types
904
+
905
+ ```javascript
906
+ /**
907
+ * @typedef {Monster & { available: number, needed: number, covers_need: boolean }} Wanted
908
+ * @property {number} available - Quantité disponible à l'échange
909
+ * @property {number} needed - Quantité nécessaire
910
+ * @property {boolean} covers_need - Si l'offre couvre entièrement le besoin
911
+ *
912
+ * @typedef {object} Match
913
+ * @property {Search} user - Utilisateur correspondant
914
+ * @property {object} quest - Quête du partenaire
915
+ * @property {string} quest.slug - Identifiant de la quête
916
+ * @property {string} quest.character_name - Nom du personnage
917
+ * @property {number} quest.parallel_quests - Nombre de quêtes parallèles
918
+ * @property {object} matches - Monstres en commun
919
+ * @property {Array<Wanted>} matches.they_have_you_want - Ils ont, vous cherchez
920
+ * @property {Array<Wanted>} matches.you_have_they_want - Vous avez, ils cherchent
921
+ * @property {number} match_score - Score de compatibilité (total de monstres en commun)
922
+ */
923
+ ```
924
+
925
+ #### Exemples
926
+
927
+ **Trouver tous les partenaires**
928
+
929
+ ```javascript
930
+ const response = await client.matchUserQuest("jean_api_key", "abcdef");
931
+
932
+ if (response.ok) {
933
+ console.log(`${response.pagination.total} partenaires trouvés`);
934
+
935
+ response.data.forEach((match) => {
936
+ console.log(`\n${match.user.username} (${match.quest.character_name})`);
937
+ console.log(`Score: ${match.match_score} monstres en commun`);
938
+ console.log(`Ils ont: ${match.matches.they_have_you_want.length}`);
939
+ console.log(`Ils cherchent: ${match.matches.you_have_they_want.length}`);
940
+ });
941
+ }
942
+ ```
943
+
944
+ **Trouver des fournisseurs**
945
+
946
+ ```javascript
947
+ // Utilisateurs proposant des monstres que vous recherchez
948
+ const response = await client.matchUserQuest("jean_api_key", "abcdef", {
949
+ direction: "they_have",
950
+ });
951
+
952
+ if (response.ok) {
953
+ response.data.forEach((match) => {
954
+ console.log(`\n${match.user.username} peut vous fournir:`);
955
+ match.matches.they_have_you_want.forEach((m) => {
956
+ console.log(`- ${m.name.fr} x${m.available} ${m.covers_need ? "✓" : ""}`);
957
+ });
958
+ });
959
+ }
960
+ ```
961
+
962
+ **Filtrer les joueurs actifs**
963
+
964
+ ```javascript
965
+ // Utilisateurs actifs dans les 7 derniers jours avec au moins 3 quêtes parallèles
966
+ const response = await client.matchUserQuest("jean_api_key", "abcdef", {
967
+ active_within_days: 7,
968
+ min_parallel_quests: 3,
969
+ });
970
+
971
+ if (response.ok) {
972
+ console.log(`${response.data.length} joueurs actifs trouvés`);
973
+ }
974
+ ```
257
975
 
258
976
  ---
259
977
 
260
- <div align="center">
978
+ ### Modifier les paramètres d'une quête utilisateur
979
+
980
+ Met à jour la configuration d'une quête (personnage, progression, paramètres d'échange).
981
+
982
+ #### Signature
261
983
 
262
- **🌟 Si ce projet vous aide, n'hésitez pas à lui donner une étoile !**
984
+ ```javascript
985
+ updateUserQuest(
986
+ user_api_key: string,
987
+ quest_slug: string,
988
+ options: {
989
+ character_name?: string,
990
+ parallel_quests?: number,
991
+ current_step?: number,
992
+ show_trades?: boolean,
993
+ trade_mode?: number,
994
+ trade_offer_threshold?: number | null,
995
+ trade_want_threshold?: number | null,
996
+ never_offer_normal?: boolean,
997
+ never_want_normal?: boolean,
998
+ never_offer_boss?: boolean,
999
+ never_want_boss?: boolean,
1000
+ never_offer_archi?: boolean,
1001
+ never_want_archi?: boolean
1002
+ }
1003
+ )
1004
+ ```
1005
+
1006
+ #### Paramètres
1007
+
1008
+ | Paramètre | Type | Description |
1009
+ | ----------------------- | ------------ | ------------------------------------------------------- |
1010
+ | `character_name` | string | Nom du personnage (max 200 caractères) |
1011
+ | `parallel_quests` | number | Nombre de quêtes en parallèle (1-20) |
1012
+ | `current_step` | number | Étape courante (1-34) |
1013
+ | `show_trades` | boolean | Visibilité de la quête dans la communauté |
1014
+ | `trade_mode` | number | 0 = Automatique, 1 = Mode expert |
1015
+ | `trade_offer_threshold` | number\|null | Seuil minimal pour proposer en mode expert (0-30) |
1016
+ | `trade_want_threshold` | number\|null | Seuil maximal pour rechercher en mode expert (0-30) |
1017
+ | `never_offer_normal` | boolean | Ne jamais proposer les monstres normaux (étapes 1-16) |
1018
+ | `never_want_normal` | boolean | Ne jamais rechercher les monstres normaux (étapes 1-16) |
1019
+ | `never_offer_boss` | boolean | Ne jamais proposer les boss (étapes 17-19) |
1020
+ | `never_want_boss` | boolean | Ne jamais rechercher les boss (étapes 17-19) |
1021
+ | `never_offer_archi` | boolean | Ne jamais proposer les archimonstres (étapes 20+) |
1022
+ | `never_want_archi` | boolean | Ne jamais rechercher les archimonstres (étapes 20+) |
1023
+
1024
+ #### Exemples
1025
+
1026
+ **Mettre à jour les infos de base**
1027
+
1028
+ ```javascript
1029
+ const response = await client.updateUserQuest("jean_api_key", "abcdef", {
1030
+ character_name: "Mon personnage",
1031
+ parallel_quests: 5,
1032
+ current_step: 12,
1033
+ show_trades: true,
1034
+ });
1035
+
1036
+ if (response.ok) {
1037
+ console.log("Quête mise à jour:", response.data);
1038
+ }
1039
+ ```
1040
+
1041
+ **Configurer le mode expert**
1042
+
1043
+ ```javascript
1044
+ const response = await client.updateUserQuest("jean_api_key", "abcdef", {
1045
+ trade_mode: 1,
1046
+ trade_offer_threshold: 6, // Ne proposer que les monstres avec 6+ exemplaires
1047
+ trade_want_threshold: 1, // Rechercher jusqu'à l'étape 1
1048
+ });
1049
+
1050
+ if (response.ok) {
1051
+ console.log("Mode expert configuré");
1052
+ }
1053
+ ```
1054
+
1055
+ **Exclure certains types de monstres**
1056
+
1057
+ ```javascript
1058
+ const response = await client.updateUserQuest("jean_api_key", "abcdef", {
1059
+ never_offer_archi: true, // Ne jamais proposer d'archimonstres
1060
+ never_want_normal: true, // Ne pas rechercher les monstres normaux
1061
+ });
1062
+
1063
+ if (response.ok) {
1064
+ console.log("Filtres appliqués");
1065
+ }
1066
+ ```
1067
+
1068
+ ---
1069
+
1070
+ ### Modifier plusieurs monstres d'une quête utilisateur
1071
+
1072
+ Met à jour les quantités possédées pour plusieurs monstres en une seule requête.
1073
+
1074
+ #### Signature
1075
+
1076
+ ```javascript
1077
+ updateUserQuestMonsters(
1078
+ user_api_key: string,
1079
+ quest_slug: string,
1080
+ monsters: Array<{ monster_name: MonsterName, quantity: number }>
1081
+ )
1082
+ ```
1083
+
1084
+ #### Paramètres
1085
+
1086
+ | Paramètre | Requis | Type | Description |
1087
+ | -------------- | ------ | ------ | --------------------------------------- |
1088
+ | `user_api_key` | ✅ | string | Clé API de l'utilisateur |
1089
+ | `quest_slug` | ✅ | string | Identifiant (slug) de la quête |
1090
+ | `monsters` | ✅ | Array | Liste des monstres à modifier (max 200) |
1091
+
1092
+ #### Contraintes
1093
+
1094
+ - `quantity` : entre 0 et 30
1095
+ - Maximum 200 monstres par requête
1096
+
1097
+ #### Types
1098
+
1099
+ ```javascript
1100
+ /**
1101
+ * @typedef {object} UpdatedMonsters
1102
+ * @property {number} updated_count - Nombre de monstres mis à jour
1103
+ * @property {Array<Monster>} monsters - Monstres mis à jour avec leurs nouvelles valeurs
1104
+ */
1105
+ ```
1106
+
1107
+ #### Exemples
1108
+
1109
+ **Mettre à jour plusieurs monstres**
1110
+
1111
+ ```javascript
1112
+ const response = await client.updateUserQuestMonsters(
1113
+ "jean_api_key",
1114
+ "abcdef",
1115
+ [
1116
+ { monster_name: "Aboub", quantity: 5 },
1117
+ { monster_name: "Bouftou", quantity: 3 },
1118
+ { monster_name: "Tofu", quantity: 10 },
1119
+ ],
1120
+ );
1121
+
1122
+ if (response.ok) {
1123
+ console.log(`${response.data.updated_count} monstres mis à jour`);
1124
+ response.data.monsters.forEach((m) => {
1125
+ console.log(`${m.name.fr}: ${m.quantity} possédés`);
1126
+ });
1127
+ }
1128
+ ```
263
1129
 
264
- [![Star on GitHub](https://img.shields.io/github/stars/ix-xs/metamob.api.svg?style=social)](https://github.com/ix-xs/metamob.api/stargazers)
1130
+ **Réinitialiser des quantités**
265
1131
 
266
- *Développé avec ❤️ pour la communauté Dofus*
1132
+ ```javascript
1133
+ const response = await client.updateUserQuestMonsters(
1134
+ "jean_api_key",
1135
+ "abcdef",
1136
+ [
1137
+ { monster_name: "Aboub", quantity: 0 },
1138
+ { monster_name: "Bouftou", quantity: 0 },
1139
+ ],
1140
+ );
1141
+
1142
+ if (response.ok) {
1143
+ console.log("Quantités réinitialisées");
1144
+ }
1145
+ ```
267
1146
 
268
1147
  ---
269
1148
 
270
- **⚡ Propulsé par l'API Metamob | Optimisé pour la performance | Conçu pour les développeurs**
1149
+ ### Paramètres de trade manuels d'une quête utilisateur
1150
+
1151
+ Force les quantités proposées/recherchées pour un monstre spécifique, remplaçant le calcul automatique.
1152
+
1153
+ #### Signature
1154
+
1155
+ ```javascript
1156
+ updateUserQuestMonsterTrade(
1157
+ user_api_key: string,
1158
+ quest_slug: string,
1159
+ monster_name: MonsterName,
1160
+ options: {
1161
+ trade_offer?: number | null,
1162
+ trade_want?: number | null
1163
+ }
1164
+ )
1165
+ ```
1166
+
1167
+ #### Paramètres
271
1168
 
272
- </div>
1169
+ | Paramètre | Requis | Type | Description |
1170
+ | -------------- | ------ | ------------ | ---------------------------------------------------------- |
1171
+ | `user_api_key` | ✅ | string | Clé API de l'utilisateur |
1172
+ | `quest_slug` | ✅ | string | Identifiant (slug) de la quête |
1173
+ | `monster_name` | ✅ | MonsterName | Nom du monstre |
1174
+ | `trade_offer` | ❌ | number\|null | Quantité à proposer (0 à owned). null = calcul automatique |
1175
+ | `trade_want` | ❌ | number\|null | Quantité recherchée (0 à 30). null = calcul automatique |
1176
+
1177
+ #### Exemples
1178
+
1179
+ **Forcer les quantités d'échange**
1180
+
1181
+ ```javascript
1182
+ const response = await client.updateUserQuestMonsterTrade(
1183
+ "jean_api_key",
1184
+ "abcdef",
1185
+ "Aboub",
1186
+ {
1187
+ trade_offer: 1, // Proposer 1 Aboub
1188
+ trade_want: 5, // Rechercher 5 Aboub
1189
+ },
1190
+ );
1191
+
1192
+ if (response.ok) {
1193
+ console.log(`${response.data.name.fr}:`);
1194
+ console.log(`- Proposé: ${response.data.trade_offer}`);
1195
+ console.log(`- Recherché: ${response.data.trade_want}`);
1196
+ }
1197
+ ```
1198
+
1199
+ **Réactiver le calcul automatique**
1200
+
1201
+ ```javascript
1202
+ const response = await client.updateUserQuestMonsterTrade(
1203
+ "jean_api_key",
1204
+ "abcdef",
1205
+ "Aboub",
1206
+ {
1207
+ trade_offer: null, // Calcul automatique
1208
+ trade_want: null, // Calcul automatique
1209
+ },
1210
+ );
1211
+
1212
+ if (response.ok) {
1213
+ console.log("Calcul automatique réactivé pour Aboub");
1214
+ }
1215
+ ```
1216
+
1217
+ **Mode hybride**
1218
+
1219
+ ```javascript
1220
+ // Proposer automatiquement, mais rechercher manuellement
1221
+ const response = await client.updateUserQuestMonsterTrade(
1222
+ "jean_api_key",
1223
+ "abcdef",
1224
+ "Bouftou",
1225
+ {
1226
+ trade_offer: null, // Auto
1227
+ trade_want: 2, // Fixe à 2
1228
+ },
1229
+ );
1230
+ ```
1231
+
1232
+ <br>
1233
+
1234
+ ## 🔗 Ressources
1235
+
1236
+ - 🌐 [Site Metamob](https://beta.metamob.fr)
1237
+ - 📖 [Documentation API Officielle](https://beta.metamob.fr/help/api)
1238
+ - 📦 [Package NPM](https://www.npmjs.com/package/@ix-xs/metamob.api)
1239
+ - 🔧 [GitHub Repository](https://github.com/ix-xs/metamob.api)
1240
+ - 💬 [Discord Metamob](https://discord.gg/SadWCNf2pk)
1241
+
1242
+ ## 🐛 Signaler un bug
1243
+
1244
+ Avez-vous trouvé un bug ? Créez une issue sur GitHub :
1245
+
1246
+ 👉 [GitHub Issues](https://github.com/ix-xs/metamob.api/issues)
1247
+
1248
+ ## 👨‍💼 Auteur
1249
+
1250
+ ![ix-xs](https://cdn.discordapp.com/avatars/782307250751406091/a_3f71f1ac5e1664038fdf33c2c408482e.gif?size=48) **ix-xs**
1251
+
1252
+ ---
1253
+
1254
+ <div align="center">
1255
+
1256
+ **Fait avec ❤️ pour la communauté Dofus**
1257
+
1258
+ ⭐ N'oubliez pas de mettre une star si ce projet vous a aidé !
1259
+
1260
+ [GitHub](https://github.com/ix-xs/metamob.api) • [NPM](https://www.npmjs.com/package/@ix-xs/metamob.api) • [Site Metamob](https://beta.metamob.fr)
1261
+
1262
+ </div>