@20syldev/api 2.8.0 → 2.9.0

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.
Files changed (3) hide show
  1. package/README.md +31 -4
  2. package/app.js +62 -59
  3. package/package.json +13 -12
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <a href="https://api.sylvain.pro"><img src="https://api.sylvain.pro/favicon.ico" alt="Logo" width="25%" height="auto"/></a>
3
3
 
4
4
  # API Personnelle
5
- [![Version](https://custom-icon-badges.demolab.com/badge/Version%20:-v2.8.0-6479ee?logo=api.sylvain.pro&labelColor=23272A)](https://github.com/20syldev/api/releases/latest)
5
+ [![Version](https://custom-icon-badges.demolab.com/badge/Version%20:-v2.9.0-6479ee?logo=api.sylvain.pro&labelColor=23272A)](https://github.com/20syldev/api/releases/latest)
6
6
  </div>
7
7
 
8
8
  ---
@@ -12,12 +12,39 @@ Voici mon API personnelle, disponible sur le domaine [api.sylvain.pro](https://a
12
12
  L'API est développée avec Node.js et hébergée **24h/7j**. Elle est **simple d'utilisation** et a une **documentation** disponible sur [docs.sylvain.pro](https://docs.sylvain.pro) !
13
13
  > *Une limite de **1000** requêtes maximum chaque **10 secondes** est fixée.*
14
14
 
15
- ## Tester l'API localement
15
+ ## Installer le paquet de l'API sur votre machine
16
+ ```console
17
+ $ sudo apt install nodejs npm
18
+ $ npm install @20syldev/api
19
+ ```
20
+
21
+ Pour utiliser le **paquet** dans votre projet, **créez** un fichier **JavaScript**. Par exemple, `index.js` :
22
+ ```js
23
+ require('@20syldev/api');
24
+ ```
25
+
26
+ Puis, **démarrez** un serveur [Node.js](http://nodejs.org) pour utiliser l'**API** :
27
+ ```console
28
+ $ node index.js
29
+ API is running on
30
+ - http://127.0.0.1:3000
31
+ - http://localhost:3000
32
+ ```
33
+ > *Remplacez `index.js` par le nom de votre fichier JavaScript.*
34
+
35
+ ## Tester l'API sur votre machine
36
+ **Téléchargez** la [dernière mise à jour](https://github.com/20syldev/api/releases/latest) de l'API, puis **extrayez** le contenu du fichier `.zip` ou `.tar.gz` dans un de vos **répertoires**.
37
+ Ensuite, **déplacez-vous** dans le dossier du projet, via un terminal **Linux**, **Windows** ou **macOS** :
38
+ ```console
39
+ $ cd /chemin/vers/le/projet
40
+ ```
41
+
42
+ Enfin, **exécutez** le script de build, qui installera les **dépendances** et lancera le **serveur** de l'[API](https://api.sylvain.pro) :
16
43
  ```console
17
44
  $ npm run build
18
45
  ```
19
46
  ```console
20
- > @20syldev/api@2.8.0 build
47
+ > @20syldev/api@2.9.0 build
21
48
  > npm install && node app.js
22
49
 
23
50
  [...]
@@ -28,4 +55,4 @@ API is running on
28
55
  - http://localhost:3000
29
56
  ```
30
57
 
31
- *Visitez la [documentation](https://docs.sylvain.pro) dédiée, vous y retrouverez des exemples de requêtes et des codes simples pour tester l'[API](https://api.sylvain.pro) !*
58
+ *Visitez la [documentation](https://docs.sylvain.pro) dédiée, vous y retrouverez des exemples de requêtes et des codes simples pour tester l'[API](https://api.sylvain.pro) !*
package/app.js CHANGED
@@ -1,18 +1,17 @@
1
- require('dotenv').config();
2
-
3
- // Built-in module
4
- const crypto = require('crypto');
5
-
6
- // Imported module
7
- const { createCanvas } = require('canvas');
8
- const cors = require('cors');
9
- const express = require('express');
10
- const fetch = require('node-fetch');
11
- const math = require('mathjs');
12
- const path = require('path');
13
- const qrcode = require('qrcode');
14
- const random = require('random');
15
- const uuid = require('uuid');
1
+ import { createCanvas } from 'canvas';
2
+ import cors from 'cors';
3
+ import dotenv from 'dotenv';
4
+ import { randomBytes, getHashes, createHash } from 'crypto';
5
+ import express, { urlencoded, json } from 'express';
6
+ import { factorial } from 'mathjs';
7
+ import fetch from 'node-fetch';
8
+ import { dirname, join } from 'path';
9
+ import { toDataURL } from 'qrcode';
10
+ import { fileURLToPath } from 'url';
11
+ import { v4 } from 'uuid';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
16
15
  const app = express();
17
16
 
18
17
  // Define allowed versions & endpoints for each version
@@ -22,6 +21,16 @@ const endpoints = {
22
21
  v2: ['algorithms', 'captcha', 'chat', 'color', 'convert', 'domain', 'hash', 'infos', 'personal', 'qrcode', 'tic-tac-toe', 'token', 'username', 'website']
23
22
  };
24
23
 
24
+ // Arrowed functions (math & random)
25
+ const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
26
+ const genID = () => {
27
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
28
+ return Array.from(randomBytes(5)).map(b => chars[b % chars.length]).join('');
29
+ };
30
+ const genIP = () => `${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`;
31
+ const genToken = (chars, length) => Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
32
+ const random = (arr) => arr[Math.floor(Math.random() * arr.length)];
33
+
25
34
  // Store data
26
35
  const logs = [], chat = [], privateChats = {}, sessions = {}, rateLimits = {}, games = {};
27
36
 
@@ -30,16 +39,18 @@ let lastFetch = 0, requests = 0, resetTime = Date.now() + 10000;
30
39
 
31
40
  // ----------- ----------- MIDDLEWARES SETUP ----------- ----------- //
32
41
 
42
+ dotenv.config();
43
+
33
44
  // CORS & Express setup
34
45
  app.use(cors({ methods: ['GET', 'POST'] }));
35
- app.use(express.urlencoded({ extended: true }));
36
- app.use(express.json());
46
+ app.use(urlencoded({ extended: true }));
47
+ app.use(json());
37
48
 
38
49
  // Set favicon for API
39
- app.use('/favicon.ico', express.static(path.join(__dirname, 'src', 'favicon.ico')));
50
+ app.use('/favicon.ico', express.static(join(__dirname, 'src', 'favicon.ico')));
40
51
 
41
52
  // Display robots.txt
42
- app.use('/robots.txt', express.static(path.join(__dirname, 'robots.txt')));
53
+ app.use('/robots.txt', express.static(join(__dirname, 'robots.txt')));
43
54
 
44
55
  // Return formatted JSON
45
56
  app.use((req, res, next) => {
@@ -104,7 +115,7 @@ app.use('/:version', (req, res, next) => {
104
115
  return res.status(404).jsonResponse({
105
116
  message: 'Not Found',
106
117
  error: `Invalid API version (${version}).`,
107
- documentation: 'https://docs.sylvain.pro',
118
+ documentation: `https://docs.sylvain.pro/${versions.at(-1)}`,
108
119
  status: '404'
109
120
  });
110
121
  }
@@ -119,7 +130,7 @@ app.use('/:version/:endpoint', (req, res, next) => {
119
130
  return res.status(404).jsonResponse({
120
131
  message: 'Not Found',
121
132
  error: `Endpoint '${endpoint}' does not exist in ${version}.`,
122
- documentation: 'https://docs.sylvain.pro',
133
+ documentation: `https://docs.sylvain.pro/${versions.at(-1)}`,
123
134
  status: '404'
124
135
  });
125
136
  }
@@ -206,11 +217,12 @@ app.get('/logs', (req, res) => res.jsonResponse(logs));
206
217
  // Algorithms
207
218
  app.get('/:version/algorithms', (req, res) => {
208
219
  const { method, value, value2 } = req.query;
220
+ const { version } = req.params;
209
221
 
210
222
  if (!['anagram', 'bubblesort', 'factorial', 'fibonacci', 'gcd', 'isprime', 'palindrome', 'primefactors', 'primelist', 'reverse'].includes(method)) {
211
223
  return res.jsonResponse({
212
224
  error: 'Please provide a valid algorithm (?method={algorithm})',
213
- documentation: 'https://docs.sylvain.pro/v1/algorithms'
225
+ documentation: `https://docs.sylvain.pro/${version}/algorithms`
214
226
  });
215
227
  }
216
228
  if (!value) return res.jsonResponse({ error: 'Please provide a valid value (&value={value})' });
@@ -233,7 +245,7 @@ app.get('/:version/algorithms', (req, res) => {
233
245
 
234
246
  if (method === 'factorial') {
235
247
  if (isNaN(value) || value < 0 || value > 170) return res.jsonResponse({ error: 'Please provide a valid number between 0 and 170.' });
236
- return res.jsonResponse({ answer: math.factorial(value) });
248
+ return res.jsonResponse({ answer: factorial(value) });
237
249
  }
238
250
 
239
251
  if (method === 'fibonacci') {
@@ -243,7 +255,6 @@ app.get('/:version/algorithms', (req, res) => {
243
255
  }
244
256
 
245
257
  if (method === 'gcd') {
246
- const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
247
258
  if (!value2) return res.jsonResponse({ error: 'Please provide a second value (&value2={value})' });
248
259
  if (isNaN(value) || isNaN(value2)) return res.jsonResponse({ error: 'Invalid numbers.' });
249
260
  return res.jsonResponse({ answer: gcd(value, value2) });
@@ -354,7 +365,7 @@ app.get('/:version/chat/private', (req, res) => {
354
365
 
355
366
  // Generate color
356
367
  app.get('/:version/color', (req, res) => {
357
- const r = random.int(0, 255), g = random.int(0, 255), b = random.int(0, 255);
368
+ const r = Math.floor(Math.random() * 256), g = Math.floor(Math.random() * 256), b = Math.floor(Math.random() * 256);
358
369
  const hsl = (() => {
359
370
  const r1 = r / 255, g1 = g / 255, b1 = b / 255, max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1), l = (max + min) / 2;
360
371
  if (max === min) return [0, 0, l * 100];
@@ -407,17 +418,15 @@ app.get('/:version/convert', (req, res) => {
407
418
 
408
419
  // Generate domain informations
409
420
  app.get('/:version/domain', (req, res) => {
410
- const random = (arr) => arr[Math.floor(Math.random() * arr.length)];
411
421
  const subdomains = ['fr.', 'en.', 'docs.', 'api.', 'projects.', 'app.', 'web.', 'info.', 'dev.', 'shop.', 'blog.', 'support.', 'mail.', 'forum.'];
412
422
  const domains = ['example', 'site', 'test', 'demo', 'page', 'store', 'portfolio', 'platform', 'hub', 'network', 'service', 'cloud', 'solutions', 'company'];
413
423
  const tlds = ['.com', '.fr', '.eu', '.dev', '.net', '.org', '.io', '.tech', '.biz', '.info', '.co', '.app', '.store', '.online', '.shop', '.tv'];
414
424
 
415
425
  const domain = `${random(domains)}${random(tlds)}`;
416
426
  const fulldomain = `${random(subdomains)}${domain}`;
417
-
418
- const getRandomIp = () => `${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`;
419
- const ips = Array.from({ length: Math.floor(Math.random() * 3) + 1 }, getRandomIp);
420
- const dns = Array.from({ length: Math.floor(Math.random() * 5) + 1 }, getRandomIp);
427
+
428
+ const ips = Array.from({ length: Math.floor(Math.random() * 3) + 1 }, genIP);
429
+ const dns = Array.from({ length: Math.floor(Math.random() * 5) + 1 }, genIP);
421
430
 
422
431
  res.jsonResponse({
423
432
  domain,
@@ -449,7 +458,7 @@ app.get('/:version/hash', (req, res) => {
449
458
  // Display API informations
450
459
  app.get('/:version/infos', (req, res) => {
451
460
  res.jsonResponse({
452
- endpoints: endpoints.length,
461
+ endpoints: endpoints[versions.at(-1)].length,
453
462
  last_version: versions.at(-1),
454
463
  documentation: 'https://docs.sylvain.pro',
455
464
  github: 'https://github.com/20syldev/api',
@@ -459,8 +468,6 @@ app.get('/:version/infos', (req, res) => {
459
468
 
460
469
  // Generate personal data
461
470
  app.get('/:version/personal', (req, res) => {
462
- const random = (arr) => arr[Math.floor(Math.random() * arr.length)];
463
-
464
471
  const people = [
465
472
  { name: 'John Doe', social: 'john_doe', email: 'john@example.com', country: 'US' },
466
473
  { name: 'Jane Martin', social: 'jane_martin', email: 'jane@example.com', country: 'FR' },
@@ -579,7 +586,7 @@ app.get('/:version/qrcode', async (req, res) => {
579
586
 
580
587
  if (!url) return res.jsonResponse({ error: 'Please provide a valid url (?url={URL})' });
581
588
 
582
- try { res.jsonResponse({ qr: await qrcode.toDataURL(url) }); }
589
+ try { res.jsonResponse({ qr: await toDataURL(url) }); }
583
590
  catch { res.jsonResponse({ error: 'Error generating QR code.' }); }
584
591
  });
585
592
 
@@ -604,7 +611,6 @@ app.get('/:version/username', (req, res) => {
604
611
  const ani = ['Cat', 'Dog', 'Tiger', 'Elephant', 'Monkey', 'Penguin', 'Dolphin', 'Lion', 'Bear', 'Fox', 'Owl', 'Giraffe', 'Zebra', 'Koala', 'Rabbit', 'Squirrel', 'Panda', 'Horse', 'Wolf', 'Eagle'];
605
612
  const job = ['Writer', 'Artist', 'Musician', 'Explorer', 'Scientist', 'Engineer', 'Athlete', 'Chef', 'Doctor', 'Teacher', 'Lawyer', 'Entrepreneur', 'Actor', 'Dancer', 'Photographer', 'Architect', 'Pilot', 'Designer', 'Journalist', 'Veterinarian'];
606
613
 
607
- const random = (arr) => arr[Math.floor(Math.random() * arr.length)];
608
614
  const nombre = Math.floor(Math.random() * 100);
609
615
  const choix = {
610
616
  adj_num: () => random(adj) + nombre,
@@ -829,12 +835,7 @@ app.post('/:version/tic-tac-toe/fetch', (req, res) => {
829
835
 
830
836
  if (!username) return res.jsonResponse({ error: 'Please provide a username (?username={username})' });
831
837
 
832
- const generateId = () => {
833
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
834
- return Array.from(crypto.randomBytes(5)).map(b => chars[b % chars.length]).join('');
835
- };
836
-
837
- const ID = game || generateId();
838
+ const ID = game || genID();
838
839
  const u = username.toLowerCase(), now = Date.now();
839
840
 
840
841
  rateLimits[u] = (rateLimits[u] || []).filter(ts => now - ts < 10000);
@@ -855,40 +856,42 @@ app.post('/:version/tic-tac-toe/fetch', (req, res) => {
855
856
  // Generate hash
856
857
  app.post('/:version/hash', (req, res) => {
857
858
  const { text, method } = req.body;
859
+ const { version } = req.params;
858
860
 
859
861
  if (!text) return res.jsonResponse({ error: 'Please provide a text (?text={text})' });
860
862
  if (!method) return res.jsonResponse({
861
863
  error: 'Please provide a valid hash algorithm (?method={algorithm})',
862
- documentation: 'https://docs.sylvain.pro/v1/hash'
864
+ documentation: `https://docs.sylvain.pro/${version}/hash`
863
865
  });
864
866
 
865
- const methods = crypto.getHashes();
867
+ const methods = getHashes();
866
868
  if (!methods.includes(method)) return res.jsonResponse({ error: `Unsupported method. Use one of: ${methods.join(', ')}` });
867
869
 
868
- const hash = crypto.createHash(method).update(text).digest('hex');
870
+ const hash = createHash(method).update(text).digest('hex');
869
871
  res.jsonResponse({ method, hash });
870
872
  });
871
873
 
872
874
  // Generate Token
873
875
  app.post('/:version/token', (req, res) => {
874
- const length = parseInt(req.body.len || 24, 10);
875
- const type = req.body.type || 'alpha';
876
+ let { len, type } = req.body;
877
+
878
+ len = parseInt(len || 24, 10);
879
+ type = type ? type.toLowerCase() : 'alpha';
876
880
 
877
- if (isNaN(length) || length < 0) return res.jsonResponse({ error: 'Invalid number.' });
878
- if (length > 4096) return res.jsonResponse({ error: 'Length cannot exceed 4096.' });
879
- if (length < 12) return res.jsonResponse({ error: 'Length cannot be less than 12.' });
881
+ if (isNaN(len) || len < 0) return res.jsonResponse({ error: 'Invalid number.' });
882
+ if (len > 4096) return res.jsonResponse({ error: 'Length cannot exceed 4096.' });
883
+ if (len < 12) return res.jsonResponse({ error: 'Length cannot be less than 12.' });
880
884
 
881
- const generateToken = (chars) => Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
882
885
  const token = {
883
- alpha: generateToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'),
884
- alphanum: generateToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'),
885
- base64: crypto.randomBytes(length).toString('base64').slice(0, length),
886
- hex: crypto.randomBytes(length).toString('hex').slice(0, length),
887
- num: generateToken('0123456789'),
888
- punct: generateToken('!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'),
889
- urlsafe: generateToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_'),
890
- uuid: uuid.v4().replace(/-/g, '').slice(0, length)
891
- }[type] || generateToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
886
+ alpha: genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', len),
887
+ alphanum: genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', len),
888
+ base64: randomBytes(len).toString('base64').slice(0, len),
889
+ hex: randomBytes(len).toString('hex').slice(0, len),
890
+ num: genToken('0123456789', len),
891
+ punct: genToken('!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~', len),
892
+ urlsafe: genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_', len),
893
+ uuid: v4().replace(/-/g, '').slice(0, len)
894
+ }[type] || genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', len);
892
895
 
893
896
  res.jsonResponse({ token });
894
897
  });
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
- "version": "2.8.0",
2
+ "version": "2.9.0",
3
3
  "name": "@20syldev/api",
4
- "description": "Personnal API",
4
+ "description": "Node.js API with multiple features. Check the documentation at https://docs.sylvain.pro",
5
5
  "main": "app.js",
6
+ "type": "module",
6
7
  "scripts": {
7
8
  "start": "node app.js",
8
9
  "build": "npm install && node app.js",
@@ -11,16 +12,16 @@
11
12
  "upgrade:build": "npm upgrade && npm install && node app.js"
12
13
  },
13
14
  "dependencies": {
14
- "canvas": "^3.1.0",
15
- "cors": "2.8.5",
16
- "dotenv": "^16.4.7",
17
- "express": "^4.21.2",
18
- "mathjs": "^14.2.0",
19
- "node-fetch": "^2.7.0",
20
- "prettier": "^3.4.2",
21
- "qrcode": "^1.5.4",
22
- "random": "^5.1.1",
23
- "uuid": "^11.0.5"
15
+ "canvas": "latest",
16
+ "cors": "latest",
17
+ "dotenv": "latest",
18
+ "express": "latest",
19
+ "mathjs": "latest",
20
+ "node-fetch": "latest",
21
+ "prettier": "latest",
22
+ "qrcode": "latest",
23
+ "random": "latest",
24
+ "uuid": "latest"
24
25
  },
25
26
  "repository": {
26
27
  "type": "git",