@20syldev/api 3.5.0 → 4.0.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.
- package/.prettierrc +7 -0
- package/README.md +32 -33
- package/dist/app.js +36 -0
- package/dist/app.js.map +1 -0
- package/dist/config/env.js +73 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/versions.js +72 -0
- package/dist/config/versions.js.map +1 -0
- package/dist/constants.js +42 -0
- package/dist/constants.js.map +1 -0
- package/dist/middleware/cors.js +15 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error.js +6 -0
- package/dist/middleware/error.js.map +1 -0
- package/dist/middleware/json.js +8 -0
- package/dist/middleware/json.js.map +1 -0
- package/dist/middleware/logger.js +26 -0
- package/dist/middleware/logger.js.map +1 -0
- package/dist/middleware/ratelimit.js +58 -0
- package/dist/middleware/ratelimit.js.map +1 -0
- package/dist/middleware/version.js +30 -0
- package/dist/middleware/version.js.map +1 -0
- package/dist/modules/v3/algorithms.js +221 -0
- package/dist/modules/v3/algorithms.js.map +1 -0
- package/{modules → dist/modules}/v3/captcha.js +4 -13
- package/dist/modules/v3/captcha.js.map +1 -0
- package/dist/modules/v3/chat.js +103 -0
- package/dist/modules/v3/chat.js.map +1 -0
- package/{modules → dist/modules}/v3/color.js +12 -13
- package/dist/modules/v3/color.js.map +1 -0
- package/dist/modules/v3/convert.js +41 -0
- package/dist/modules/v3/convert.js.map +1 -0
- package/dist/modules/v3/domain.js +83 -0
- package/dist/modules/v3/domain.js.map +1 -0
- package/dist/modules/v3/hash.js +16 -0
- package/dist/modules/v3/hash.js.map +1 -0
- package/dist/modules/v3/hyperplanning.js +50 -0
- package/dist/modules/v3/hyperplanning.js.map +1 -0
- package/dist/modules/v3/levenshtein.js +38 -0
- package/dist/modules/v3/levenshtein.js.map +1 -0
- package/dist/modules/v3/personal.js +129 -0
- package/dist/modules/v3/personal.js.map +1 -0
- package/dist/modules/v3/qrcode.js +21 -0
- package/dist/modules/v3/qrcode.js.map +1 -0
- package/dist/modules/v3/tic_tac_toe.js +221 -0
- package/dist/modules/v3/tic_tac_toe.js.map +1 -0
- package/dist/modules/v3/time.js +88 -0
- package/dist/modules/v3/time.js.map +1 -0
- package/{modules → dist/modules}/v3/token.js +10 -11
- package/dist/modules/v3/token.js.map +1 -0
- package/dist/modules/v3/username.js +92 -0
- package/dist/modules/v3/username.js.map +1 -0
- package/dist/modules/v3/utils.js +70 -0
- package/dist/modules/v3/utils.js.map +1 -0
- package/dist/modules/v3.js +16 -0
- package/dist/modules/v3.js.map +1 -0
- package/dist/modules/v4/algorithms.js +200 -0
- package/dist/modules/v4/algorithms.js.map +1 -0
- package/dist/modules/v4/captcha.js +35 -0
- package/dist/modules/v4/captcha.js.map +1 -0
- package/dist/modules/v4/chat.js +92 -0
- package/dist/modules/v4/chat.js.map +1 -0
- package/dist/modules/v4/color.js +43 -0
- package/dist/modules/v4/color.js.map +1 -0
- package/dist/modules/v4/convert.js +33 -0
- package/dist/modules/v4/convert.js.map +1 -0
- package/dist/modules/v4/dice.js +30 -0
- package/dist/modules/v4/dice.js.map +1 -0
- package/dist/modules/v4/domain.js +78 -0
- package/dist/modules/v4/domain.js.map +1 -0
- package/dist/modules/v4/encode.js +165 -0
- package/dist/modules/v4/encode.js.map +1 -0
- package/dist/modules/v4/geo.js +41 -0
- package/dist/modules/v4/geo.js.map +1 -0
- package/dist/modules/v4/hash.js +9 -0
- package/dist/modules/v4/hash.js.map +1 -0
- package/dist/modules/v4/hyperplanning.js +42 -0
- package/dist/modules/v4/hyperplanning.js.map +1 -0
- package/dist/modules/v4/levenshtein.js +29 -0
- package/dist/modules/v4/levenshtein.js.map +1 -0
- package/dist/modules/v4/palette.js +89 -0
- package/dist/modules/v4/palette.js.map +1 -0
- package/dist/modules/v4/personal.js +125 -0
- package/dist/modules/v4/personal.js.map +1 -0
- package/dist/modules/v4/placeholder.js +96 -0
- package/dist/modules/v4/placeholder.js.map +1 -0
- package/dist/modules/v4/qrcode.js +12 -0
- package/dist/modules/v4/qrcode.js.map +1 -0
- package/dist/modules/v4/statistics.js +41 -0
- package/dist/modules/v4/statistics.js.map +1 -0
- package/dist/modules/v4/text.js +293 -0
- package/dist/modules/v4/text.js.map +1 -0
- package/dist/modules/v4/tic_tac_toe.js +206 -0
- package/dist/modules/v4/tic_tac_toe.js.map +1 -0
- package/dist/modules/v4/time.js +73 -0
- package/dist/modules/v4/time.js.map +1 -0
- package/dist/modules/v4/token.js +36 -0
- package/dist/modules/v4/token.js.map +1 -0
- package/dist/modules/v4/username.js +87 -0
- package/dist/modules/v4/username.js.map +1 -0
- package/dist/modules/v4/utils.js +26 -0
- package/dist/modules/v4/utils.js.map +1 -0
- package/dist/modules/v4/validate.js +54 -0
- package/dist/modules/v4/validate.js.map +1 -0
- package/dist/modules/v4.js +18 -0
- package/dist/modules/v4.js.map +1 -0
- package/dist/routes/delete.js +65 -0
- package/dist/routes/delete.js.map +1 -0
- package/dist/routes/get.js +441 -0
- package/dist/routes/get.js.map +1 -0
- package/dist/routes/index.js +50 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/patch.js +41 -0
- package/dist/routes/patch.js.map +1 -0
- package/dist/routes/post.js +185 -0
- package/dist/routes/post.js.map +1 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types/storage.js +2 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/utils/response.js +10 -0
- package/dist/utils/response.js.map +1 -0
- package/dist/utils/version.js +3 -0
- package/dist/utils/version.js.map +1 -0
- package/eslint.config.js +20 -0
- package/package.json +30 -15
- package/src/app.ts +44 -0
- package/src/config/env.ts +81 -0
- package/src/config/versions.ts +80 -0
- package/src/constants.ts +28 -0
- package/src/middleware/cors.ts +17 -0
- package/src/middleware/error.ts +7 -0
- package/src/middleware/json.ts +9 -0
- package/src/middleware/logger.ts +31 -0
- package/src/middleware/ratelimit.ts +66 -0
- package/src/middleware/version.ts +39 -0
- package/{modules → src/modules}/v3/algorithms.js +1 -1
- package/src/modules/v3/captcha.js +60 -0
- package/{modules → src/modules}/v3/chat.js +6 -4
- package/src/modules/v3/color.js +60 -0
- package/{modules → src/modules}/v3/convert.js +5 -5
- package/{modules → src/modules}/v3/domain.js +51 -4
- package/{modules → src/modules}/v3/hash.js +1 -1
- package/{modules → src/modules}/v3/hyperplanning.js +11 -10
- package/{modules → src/modules}/v3/levenshtein.js +3 -3
- package/{modules → src/modules}/v3/personal.js +20 -8
- package/{modules → src/modules}/v3/qrcode.js +1 -1
- package/{modules → src/modules}/v3/tic_tac_toe.js +24 -18
- package/{modules → src/modules}/v3/time.js +22 -11
- package/src/modules/v3/token.js +54 -0
- package/src/modules/v3/username.js +94 -0
- package/{modules → src/modules}/v3/utils.js +2 -2
- package/{modules → src/modules}/v3.js +1 -1
- package/src/modules/v4/algorithms.ts +155 -0
- package/src/modules/v4/captcha.ts +49 -0
- package/src/modules/v4/chat.ts +99 -0
- package/src/modules/v4/color.ts +64 -0
- package/src/modules/v4/convert.ts +38 -0
- package/src/modules/v4/domain.ts +81 -0
- package/src/modules/v4/hash.ts +9 -0
- package/src/modules/v4/hyperplanning.ts +58 -0
- package/src/modules/v4/levenshtein.ts +38 -0
- package/src/modules/v4/personal.ts +147 -0
- package/src/modules/v4/qrcode.ts +11 -0
- package/src/modules/v4/tic_tac_toe.ts +223 -0
- package/src/modules/v4/time.ts +92 -0
- package/src/modules/v4/token.ts +43 -0
- package/src/modules/v4/username.ts +89 -0
- package/src/modules/v4/utils.ts +38 -0
- package/src/modules/v4.ts +15 -0
- package/src/routes/get.ts +461 -0
- package/src/routes/index.ts +58 -0
- package/src/routes/post.ts +200 -0
- package/src/storage/index.ts +16 -0
- package/src/types/express.d.ts +17 -0
- package/src/types/storage.ts +48 -0
- package/src/utils/response.ts +11 -0
- package/tsconfig.json +17 -0
- package/app.js +0 -865
- package/modules/v3/username.js +0 -32
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { env } from '../config/env.js';
|
|
3
|
+
import { ipLimits } from '../storage/index.js';
|
|
4
|
+
import { SESSION_TTL } from '../constants.js';
|
|
5
|
+
import { error } from '../utils/response.js';
|
|
6
|
+
|
|
7
|
+
let requests = 0;
|
|
8
|
+
let resetTime = Date.now() + SESSION_TTL;
|
|
9
|
+
|
|
10
|
+
export function rateLimitMiddleware(req: Request, res: Response, next: NextFunction): void {
|
|
11
|
+
const ip = (req.headers['cf-connecting-ip'] as string) || req.socket.remoteAddress || '';
|
|
12
|
+
const token = req.headers.authorization?.split(' ')[1] || '';
|
|
13
|
+
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const minute = String(Math.floor(now / 60000) % 60);
|
|
16
|
+
const hour = String(Math.floor(now / 3600000) % 24);
|
|
17
|
+
|
|
18
|
+
if (
|
|
19
|
+
(token && ![...env.BUSINESS_TOKEN_LIST, ...env.PRO_TOKEN_LIST, ...env.ADVANCED_TOKEN_LIST].includes(token)) ||
|
|
20
|
+
token === 'undefined'
|
|
21
|
+
) {
|
|
22
|
+
error(res, 401, 'Invalid token.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let requestLimit: number;
|
|
27
|
+
if (env.BUSINESS_TOKEN_LIST.includes(token) && !env.BUSINESS_TOKEN_LIST.includes('undefined')) {
|
|
28
|
+
requestLimit = env.BUSINESS_LIMIT;
|
|
29
|
+
} else if (env.PRO_TOKEN_LIST.includes(token) && !env.PRO_TOKEN_LIST.includes('undefined')) {
|
|
30
|
+
requestLimit = env.PRO_LIMIT;
|
|
31
|
+
} else if (env.ADVANCED_TOKEN_LIST.includes(token) && !env.ADVANCED_TOKEN_LIST.includes('undefined')) {
|
|
32
|
+
requestLimit = env.ADVANCED_LIMIT;
|
|
33
|
+
} else {
|
|
34
|
+
requestLimit = env.DEFAULT_LIMIT;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (now > resetTime) {
|
|
38
|
+
requests = 0;
|
|
39
|
+
resetTime = now + SESSION_TTL;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (++requests > Math.max(env.GLOBAL_LIMIT, requestLimit)) {
|
|
43
|
+
error(res, 429, 'Global rate limit exceeded.');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (['__proto__', 'constructor', 'prototype'].includes(ip)) {
|
|
48
|
+
error(res, 400, 'Invalid IP address.');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!ipLimits[ip]) ipLimits[ip] = {};
|
|
53
|
+
if (!ipLimits[ip]![hour]) ipLimits[ip]![hour] = {};
|
|
54
|
+
ipLimits[ip]![hour]![minute] = (ipLimits[ip]![hour]![minute] ?? 0) + 1;
|
|
55
|
+
|
|
56
|
+
if (ipLimits[ip]![hour]![minute]! > requestLimit) {
|
|
57
|
+
error(res, 429, `You have exceeded the limit of ${requestLimit} requests per hour.`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Object.keys(ipLimits[ip]!).forEach((h) => {
|
|
62
|
+
if (h != hour) delete ipLimits[ip]![h];
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
next();
|
|
66
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { versions } from '../config/versions.js';
|
|
3
|
+
import { error } from '../utils/response.js';
|
|
4
|
+
|
|
5
|
+
export function versionCheckMiddleware(req: Request, res: Response, next: NextFunction): void {
|
|
6
|
+
const version = req.params.version as string;
|
|
7
|
+
const latest = Object.keys(versions).pop()!;
|
|
8
|
+
|
|
9
|
+
req.version = version;
|
|
10
|
+
req.latest = latest;
|
|
11
|
+
|
|
12
|
+
if (!versions[version]) {
|
|
13
|
+
error(res, 404, `Invalid API version (${version}).`, latest);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
req.module = versions[version]!.modules;
|
|
18
|
+
|
|
19
|
+
if (!req.module) {
|
|
20
|
+
error(res, 404, `Module not found for version ${version}.`, latest);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
next();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function endpointCheckMiddleware(req: Request, res: Response, next: NextFunction): void {
|
|
28
|
+
const version = req.params.version as string;
|
|
29
|
+
const endpoint = req.params.endpoint as string;
|
|
30
|
+
|
|
31
|
+
req.version = version;
|
|
32
|
+
req.endpoint = endpoint;
|
|
33
|
+
|
|
34
|
+
if (!endpoint) {
|
|
35
|
+
error(res, 404, `Endpoint '${endpoint}' does not exist in ${req.version}.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
next();
|
|
39
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createCanvas } from 'canvas';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a captcha image from the provided text
|
|
5
|
+
*
|
|
6
|
+
* @param {string} text - Text to render in the captcha image
|
|
7
|
+
* @returns {Buffer} - PNG image buffer of the rendered captcha
|
|
8
|
+
* @throws {Error} - If text is not provided
|
|
9
|
+
*/
|
|
10
|
+
export default function captcha(text) {
|
|
11
|
+
if (!text) throw new Error('Text is required to generate a captcha.');
|
|
12
|
+
|
|
13
|
+
const size = 60,
|
|
14
|
+
font = '60px Comic Sans Ms',
|
|
15
|
+
width = text.length * size,
|
|
16
|
+
height = 120;
|
|
17
|
+
const canvas = createCanvas(width, height),
|
|
18
|
+
ctx = canvas.getContext('2d');
|
|
19
|
+
|
|
20
|
+
// Set white background
|
|
21
|
+
ctx.fillStyle = 'white';
|
|
22
|
+
ctx.fillRect(0, 0, width, height);
|
|
23
|
+
|
|
24
|
+
// Add random lines for noise
|
|
25
|
+
for (let i = 0; i < 20; i++) {
|
|
26
|
+
ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
|
|
27
|
+
ctx.beginPath();
|
|
28
|
+
ctx.moveTo(Math.random() * width, Math.random() * height);
|
|
29
|
+
ctx.lineTo(Math.random() * width, Math.random() * height);
|
|
30
|
+
ctx.lineWidth = Math.random() * 2;
|
|
31
|
+
ctx.stroke();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let x = (canvas.width + 20 - width) / 2;
|
|
35
|
+
|
|
36
|
+
// Draw each character with random rotation and color
|
|
37
|
+
for (let i = 0; i < text.length; i++) {
|
|
38
|
+
const offsetX = Math.cos(i * 0.3) * 10,
|
|
39
|
+
y = height / 2.5 + Math.floor(Math.random() * (height / 2));
|
|
40
|
+
|
|
41
|
+
ctx.font = font;
|
|
42
|
+
ctx.fillStyle = `rgb(${Math.floor(Math.random() * 192)}, ${Math.floor(Math.random() * 192)}, ${Math.floor(Math.random() * 192)})`;
|
|
43
|
+
|
|
44
|
+
ctx.save();
|
|
45
|
+
ctx.translate(x + size / 2, y);
|
|
46
|
+
ctx.rotate((Math.random() - 0.5) * 0.5);
|
|
47
|
+
ctx.fillText(text[i], -size / 2 + offsetX, 0);
|
|
48
|
+
ctx.restore();
|
|
49
|
+
|
|
50
|
+
x += size;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Add noise dots
|
|
54
|
+
for (let i = 0; i < 200; i++) {
|
|
55
|
+
ctx.fillStyle = 'black';
|
|
56
|
+
ctx.fillRect(Math.floor(Math.random() * width), Math.floor(Math.random() * height), 1.2, 1.2);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return canvas.toBuffer('image/png');
|
|
60
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { checkRateLimit } from
|
|
1
|
+
import { checkRateLimit } from './utils.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Manages a chat system with public and private messages
|
|
@@ -61,14 +61,16 @@ function sendMessage(params, messages, privateChats, sessions, u, now) {
|
|
|
61
61
|
const msg = {
|
|
62
62
|
username: params.username,
|
|
63
63
|
message,
|
|
64
|
-
timestamp: params.timestamp || new Date().toISOString()
|
|
64
|
+
timestamp: params.timestamp || new Date().toISOString(),
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
// Store message based on whether it's private or public
|
|
68
68
|
if (token) {
|
|
69
69
|
privateChats[token] = privateChats[token] || [];
|
|
70
70
|
privateChats[token].push(msg);
|
|
71
|
-
setTimeout(() => {
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
delete privateChats[token];
|
|
73
|
+
}, 3600000);
|
|
72
74
|
} else {
|
|
73
75
|
messages.push(msg);
|
|
74
76
|
setTimeout(() => messages.splice(messages.indexOf(msg), 1), 3600000);
|
|
@@ -106,4 +108,4 @@ function getPrivateChat(params, privateChats) {
|
|
|
106
108
|
function fetchMessages(messages) {
|
|
107
109
|
if (messages.length > 0) return messages;
|
|
108
110
|
throw new Error('No messages stored.');
|
|
109
|
-
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a random color in multiple formats
|
|
3
|
+
*
|
|
4
|
+
* @returns {Object} Color in various formats (hex, rgb, hsl, hsv, hwb, cmyk)
|
|
5
|
+
*/
|
|
6
|
+
export default function color() {
|
|
7
|
+
const r = Math.floor(Math.random() * 256),
|
|
8
|
+
g = Math.floor(Math.random() * 256),
|
|
9
|
+
b = Math.floor(Math.random() * 256);
|
|
10
|
+
|
|
11
|
+
const hsl = (() => {
|
|
12
|
+
const r1 = r / 255,
|
|
13
|
+
g1 = g / 255,
|
|
14
|
+
b1 = b / 255,
|
|
15
|
+
max = Math.max(r1, g1, b1),
|
|
16
|
+
min = Math.min(r1, g1, b1),
|
|
17
|
+
l = (max + min) / 2;
|
|
18
|
+
if (max === min) return [0, 0, l * 100];
|
|
19
|
+
const d = max - min,
|
|
20
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
21
|
+
let h = { [r1]: (g1 - b1) / d + (g1 < b1 ? 6 : 0), [g1]: (b1 - r1) / d + 2, [b1]: (r1 - g1) / d + 4 }[max];
|
|
22
|
+
return [(h * 60) % 360, s * 100, l * 100];
|
|
23
|
+
})();
|
|
24
|
+
|
|
25
|
+
const hsv = (() => {
|
|
26
|
+
const max = Math.max(r, g, b),
|
|
27
|
+
min = Math.min(r, g, b),
|
|
28
|
+
v = max / 255,
|
|
29
|
+
s = max ? (max - min) / max : 0;
|
|
30
|
+
let h =
|
|
31
|
+
max === min
|
|
32
|
+
? 0
|
|
33
|
+
: { [r]: (g - b) / (max - min), [g]: 2 + (b - r) / (max - min), [b]: 4 + (r - g) / (max - min) }[max];
|
|
34
|
+
return [(h * 60) % 360, s * 100, v * 100];
|
|
35
|
+
})();
|
|
36
|
+
|
|
37
|
+
const hwb = (() => {
|
|
38
|
+
const [h] = hsv,
|
|
39
|
+
whiteness = Math.min(r, g, b) / 255,
|
|
40
|
+
blackness = 1 - Math.max(r, g, b) / 255;
|
|
41
|
+
return [h, whiteness * 100, blackness * 100];
|
|
42
|
+
})();
|
|
43
|
+
|
|
44
|
+
const cmyk = (() => {
|
|
45
|
+
const k = 1 - Math.max(r, g, b) / 255,
|
|
46
|
+
c = (1 - r / 255 - k) / (1 - k) || 0,
|
|
47
|
+
m = (1 - g / 255 - k) / (1 - k) || 0,
|
|
48
|
+
y = (1 - b / 255 - k) / (1 - k) || 0;
|
|
49
|
+
return [c, m, y, k].map((x) => x * 100);
|
|
50
|
+
})();
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
hex: `#${[r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('')}`,
|
|
54
|
+
rgb: `rgb(${r}, ${g}, ${b})`,
|
|
55
|
+
hsl: `hsl(${hsl[0].toFixed(1)}, ${hsl[1].toFixed(1)}%, ${hsl[2].toFixed(1)}%)`,
|
|
56
|
+
hsv: `hsv(${hsv[0].toFixed(1)}, ${hsv[1].toFixed(1)}%, ${hsv[2].toFixed(1)}%)`,
|
|
57
|
+
hwb: `hwb(${hwb[0].toFixed(1)}, ${hwb[1].toFixed(1)}%, ${hwb[2].toFixed(1)}%)`,
|
|
58
|
+
cmyk: `cmyk(${cmyk.map((x) => x.toFixed(1)).join('%, ')}%)`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -11,15 +11,15 @@ export default function convert(value, from, to) {
|
|
|
11
11
|
const conversions = {
|
|
12
12
|
celsius: {
|
|
13
13
|
fahrenheit: (val) => (val * 9) / 5 + 32,
|
|
14
|
-
kelvin: (val) => val + 273.15
|
|
14
|
+
kelvin: (val) => val + 273.15,
|
|
15
15
|
},
|
|
16
16
|
fahrenheit: {
|
|
17
17
|
celsius: (val) => ((val - 32) * 5) / 9,
|
|
18
|
-
kelvin: (val) => ((val - 32) * 5) / 9 + 273.15
|
|
18
|
+
kelvin: (val) => ((val - 32) * 5) / 9 + 273.15,
|
|
19
19
|
},
|
|
20
20
|
kelvin: {
|
|
21
21
|
celsius: (val) => val - 273.15,
|
|
22
|
-
fahrenheit: (val) => ((val - 273.15) * 9) / 5 + 32
|
|
22
|
+
fahrenheit: (val) => ((val - 273.15) * 9) / 5 + 32,
|
|
23
23
|
},
|
|
24
24
|
};
|
|
25
25
|
|
|
@@ -34,6 +34,6 @@ export default function convert(value, from, to) {
|
|
|
34
34
|
from,
|
|
35
35
|
to,
|
|
36
36
|
value: parseFloat(value),
|
|
37
|
-
result: convert(parseFloat(value))
|
|
37
|
+
result: convert(parseFloat(value)),
|
|
38
38
|
};
|
|
39
|
-
}
|
|
39
|
+
}
|
|
@@ -6,9 +6,56 @@ import { random, genIP } from './utils.js';
|
|
|
6
6
|
* @returns {Object} Domain details including DNS, hosting, and SEO metrics
|
|
7
7
|
*/
|
|
8
8
|
export default function domain() {
|
|
9
|
-
const subdomains = [
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const subdomains = [
|
|
10
|
+
'fr.',
|
|
11
|
+
'en.',
|
|
12
|
+
'docs.',
|
|
13
|
+
'api.',
|
|
14
|
+
'projects.',
|
|
15
|
+
'app.',
|
|
16
|
+
'web.',
|
|
17
|
+
'info.',
|
|
18
|
+
'dev.',
|
|
19
|
+
'shop.',
|
|
20
|
+
'blog.',
|
|
21
|
+
'support.',
|
|
22
|
+
'mail.',
|
|
23
|
+
'forum.',
|
|
24
|
+
];
|
|
25
|
+
const domains = [
|
|
26
|
+
'example',
|
|
27
|
+
'site',
|
|
28
|
+
'test',
|
|
29
|
+
'demo',
|
|
30
|
+
'page',
|
|
31
|
+
'store',
|
|
32
|
+
'portfolio',
|
|
33
|
+
'platform',
|
|
34
|
+
'hub',
|
|
35
|
+
'network',
|
|
36
|
+
'service',
|
|
37
|
+
'cloud',
|
|
38
|
+
'solutions',
|
|
39
|
+
'company',
|
|
40
|
+
];
|
|
41
|
+
const tlds = [
|
|
42
|
+
'.com',
|
|
43
|
+
'.fr',
|
|
44
|
+
'.eu',
|
|
45
|
+
'.dev',
|
|
46
|
+
'.net',
|
|
47
|
+
'.org',
|
|
48
|
+
'.io',
|
|
49
|
+
'.tech',
|
|
50
|
+
'.biz',
|
|
51
|
+
'.info',
|
|
52
|
+
'.co',
|
|
53
|
+
'.app',
|
|
54
|
+
'.store',
|
|
55
|
+
'.online',
|
|
56
|
+
'.shop',
|
|
57
|
+
'.tv',
|
|
58
|
+
];
|
|
12
59
|
|
|
13
60
|
const domain = `${random(domains)}${random(tlds)}`;
|
|
14
61
|
const fulldomain = `${random(subdomains)}${domain}`;
|
|
@@ -36,4 +83,4 @@ export default function domain() {
|
|
|
36
83
|
creation_date: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toISOString(),
|
|
37
84
|
expiration_date: new Date(Date.now() + Math.floor(Math.random() * 10000000000)).toISOString(),
|
|
38
85
|
};
|
|
39
|
-
}
|
|
86
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { formatDate } from './utils.js';
|
|
2
2
|
import ical from 'ical.js';
|
|
3
|
-
import fetch from 'node-fetch';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Parse an ICS calendar file and extract event information
|
|
@@ -19,24 +18,26 @@ export default async function hyperplanning(url, detail) {
|
|
|
19
18
|
|
|
20
19
|
const events = new ical.Component(ical.parse(await response.text()))
|
|
21
20
|
.getAllSubcomponents('vevent')
|
|
22
|
-
.map(e => {
|
|
21
|
+
.map((e) => {
|
|
23
22
|
const evt = new ical.Event(e);
|
|
24
|
-
const summary = (evt.summary || '').split(' ').filter(part => part !== '-');
|
|
23
|
+
const summary = (evt.summary || '').split(' ').filter((part) => part !== '-');
|
|
25
24
|
const start = formatDate(evt.startDate.toJSDate());
|
|
26
25
|
const end = formatDate(evt.endDate.toJSDate());
|
|
27
26
|
|
|
28
27
|
if (detail === 'full') {
|
|
29
|
-
const desc = (evt.description || '').split('\n').map(l => l.trim());
|
|
30
|
-
const extract = (p) => (desc.find(l => l.startsWith(p)) || '').replace(p, '').trim();
|
|
28
|
+
const desc = (evt.description || '').split('\n').map((l) => l.trim());
|
|
29
|
+
const extract = (p) => (desc.find((l) => l.startsWith(p)) || '').replace(p, '').trim();
|
|
31
30
|
|
|
32
31
|
return {
|
|
33
32
|
summary,
|
|
34
33
|
subject: extract('Matière :'),
|
|
35
34
|
teacher: extract('Enseignant :'),
|
|
36
|
-
classes: extract('Promotions :')
|
|
35
|
+
classes: extract('Promotions :')
|
|
36
|
+
.split(', ')
|
|
37
|
+
.map((c) => c.trim()),
|
|
37
38
|
type: extract('Salle :') || undefined,
|
|
38
39
|
start,
|
|
39
|
-
end
|
|
40
|
+
end,
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -45,11 +46,11 @@ export default async function hyperplanning(url, detail) {
|
|
|
45
46
|
return {
|
|
46
47
|
summary: evt.summary || '',
|
|
47
48
|
start,
|
|
48
|
-
end
|
|
49
|
+
end,
|
|
49
50
|
};
|
|
50
51
|
})
|
|
51
52
|
.sort((a, b) => new Date(a.start) - new Date(b.start))
|
|
52
|
-
.filter(e => new Date(e.end) >= new Date());
|
|
53
|
+
.filter((e) => new Date(e.end) >= new Date());
|
|
53
54
|
|
|
54
55
|
return events;
|
|
55
|
-
}
|
|
56
|
+
}
|
|
@@ -33,7 +33,7 @@ export default function levenshtein(str1, str2) {
|
|
|
33
33
|
m[i][j] = Math.min(
|
|
34
34
|
m[i - 1][j] + 1,
|
|
35
35
|
m[i][j - 1] + 1,
|
|
36
|
-
m[i - 1][j - 1] + (str1[i - 1] !== str2[j - 1] ? 1 : 0)
|
|
36
|
+
m[i - 1][j - 1] + (str1[i - 1] !== str2[j - 1] ? 1 : 0),
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -41,6 +41,6 @@ export default function levenshtein(str1, str2) {
|
|
|
41
41
|
return {
|
|
42
42
|
str1,
|
|
43
43
|
str2,
|
|
44
|
-
distance: m[str1.length][str2.length]
|
|
44
|
+
distance: m[str1.length][str2.length],
|
|
45
45
|
};
|
|
46
|
-
}
|
|
46
|
+
}
|
|
@@ -16,7 +16,7 @@ export default function personal() {
|
|
|
16
16
|
{ name: 'Daniel Brown', social: 'daniel_brown', email: 'daniel@example.com', country: 'JP' },
|
|
17
17
|
{ name: 'Sophia Wilson', social: 'sophia_wilson', email: 'sophia@example.com', country: 'BR' },
|
|
18
18
|
{ name: 'James Taylor', social: 'james_taylor', email: 'james@example.com', country: 'CA' },
|
|
19
|
-
{ name: 'Olivia Thomas', social: 'olivia_thomas', email: 'olivia@example.com', country: 'AU' }
|
|
19
|
+
{ name: 'Olivia Thomas', social: 'olivia_thomas', email: 'olivia@example.com', country: 'AU' },
|
|
20
20
|
];
|
|
21
21
|
|
|
22
22
|
const countries = {
|
|
@@ -29,12 +29,24 @@ export default function personal() {
|
|
|
29
29
|
JP: { tel: '080-1234-5678', code: '81', lang: 'Japanese' },
|
|
30
30
|
BR: { tel: '(11) 98765-4321', code: '55', lang: 'Portuguese' },
|
|
31
31
|
CA: { tel: '416-123-4567', code: '1', lang: 'English' },
|
|
32
|
-
AU: { tel: '0412 345 678', code: '61', lang: 'English' }
|
|
32
|
+
AU: { tel: '0412 345 678', code: '61', lang: 'English' },
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
const jobs = ['Writer', 'Artist', 'Musician', 'Explorer', 'Scientist', 'Engineer', 'Athlete', 'Doctor'];
|
|
36
36
|
const hobbies = ['Reading', 'Traveling', 'Gaming', 'Cooking', 'Fitness', 'Music', 'Photography', 'Writing'];
|
|
37
|
-
const cities = [
|
|
37
|
+
const cities = [
|
|
38
|
+
'New York',
|
|
39
|
+
'Paris',
|
|
40
|
+
'London',
|
|
41
|
+
'Madrid',
|
|
42
|
+
'Berlin',
|
|
43
|
+
'Rome',
|
|
44
|
+
'Tokyo',
|
|
45
|
+
'Los Angeles',
|
|
46
|
+
'Sydney',
|
|
47
|
+
'São Paulo',
|
|
48
|
+
'Toronto',
|
|
49
|
+
];
|
|
38
50
|
const streets = ['Main St', '2nd Ave', 'Broadway', 'Park Lane', 'Elm St', 'Sunset Blvd', 'Maple St', 'Highland Rd'];
|
|
39
51
|
|
|
40
52
|
const card = Array.from({ length: 4 }, () => randomNumber(1000, 9999)).join(' ');
|
|
@@ -66,7 +78,7 @@ export default function personal() {
|
|
|
66
78
|
let emergencyContact = random(people);
|
|
67
79
|
while (
|
|
68
80
|
emergencyContact.email === person.email ||
|
|
69
|
-
emergencyContacts.some(e => e.email === emergencyContact.email)
|
|
81
|
+
emergencyContacts.some((e) => e.email === emergencyContact.email)
|
|
70
82
|
) {
|
|
71
83
|
emergencyContact = random(people);
|
|
72
84
|
}
|
|
@@ -74,7 +86,7 @@ export default function personal() {
|
|
|
74
86
|
emergencyContacts.push({
|
|
75
87
|
name: emergencyContact.name,
|
|
76
88
|
relationship: random(['Spouse', 'Parent', 'Sibling', 'Friend']),
|
|
77
|
-
phone: `+${countries[country].code} ${emergencyPhone}
|
|
89
|
+
phone: `+${countries[country].code} ${emergencyPhone}`,
|
|
78
90
|
});
|
|
79
91
|
}
|
|
80
92
|
|
|
@@ -113,15 +125,15 @@ export default function personal() {
|
|
|
113
125
|
twitter: `@${social}`,
|
|
114
126
|
facebook: `facebook.com/${social}`,
|
|
115
127
|
linkedin: `linkedin.com/in/${social}`,
|
|
116
|
-
instagram: `instagram.com/${social}
|
|
128
|
+
instagram: `instagram.com/${social}`,
|
|
117
129
|
},
|
|
118
130
|
year_income: `${yearIncome} USD/year`,
|
|
119
131
|
month_income: `${(yearIncome / 12).toFixed(2)} USD/month`,
|
|
120
|
-
education: random(['High School',
|
|
132
|
+
education: random(['High School', "Bachelor's", "Master's", 'PhD']),
|
|
121
133
|
work_experience: `${randomNumber(0, 20)} years`,
|
|
122
134
|
health_status: random(['Healthy', 'Minor Issues', 'Chronic Conditions']),
|
|
123
135
|
emergency_contacts: emergencyContacts,
|
|
124
136
|
subscriptions,
|
|
125
137
|
pets,
|
|
126
138
|
};
|
|
127
|
-
}
|
|
139
|
+
}
|
|
@@ -30,7 +30,7 @@ export default function tic_tac_toe(action, params = {}) {
|
|
|
30
30
|
const now = Date.now();
|
|
31
31
|
|
|
32
32
|
// Rate limiting
|
|
33
|
-
rateLimits[u] = (rateLimits[u] || []).filter(ts => now - ts < 10000);
|
|
33
|
+
rateLimits[u] = (rateLimits[u] || []).filter((ts) => now - ts < 10000);
|
|
34
34
|
if (rateLimits[u].length > 50) {
|
|
35
35
|
const remainingTime = Math.ceil((rateLimits[u][0] + 10000 - now) / 1000);
|
|
36
36
|
throw new Error(`Rate limit exceeded. Try again in ${remainingTime} seconds.`);
|
|
@@ -70,12 +70,12 @@ function playMove(params, games, sessions, u, now) {
|
|
|
70
70
|
moves: [],
|
|
71
71
|
players: [],
|
|
72
72
|
private: params.private || false,
|
|
73
|
-
creation: Date.now()
|
|
73
|
+
creation: Date.now(),
|
|
74
74
|
};
|
|
75
75
|
const moves = games[game].moves;
|
|
76
76
|
|
|
77
77
|
// Check if game is full
|
|
78
|
-
const players = [...new Set(moves.map(play => play.username))];
|
|
78
|
+
const players = [...new Set(moves.map((play) => play.username))];
|
|
79
79
|
if (players.length >= 2 && !players.includes(params.username)) {
|
|
80
80
|
throw new Error('Game is full, you can only watch.');
|
|
81
81
|
}
|
|
@@ -86,7 +86,7 @@ function playMove(params, games, sessions, u, now) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// Check if move is already made
|
|
89
|
-
if (moves.some(play => play.move === move)) {
|
|
89
|
+
if (moves.some((play) => play.move === move)) {
|
|
90
90
|
throw new Error('Move already made. Please choose a different move.');
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -99,8 +99,8 @@ function playMove(params, games, sessions, u, now) {
|
|
|
99
99
|
if (result.winner || result.tie) {
|
|
100
100
|
setTimeout(() => delete games[game], 600000);
|
|
101
101
|
return {
|
|
102
|
-
message: `Move sent successfully. ${result.winner ? result.winner + ' wins. ' + result.loser + ' loses.' :
|
|
103
|
-
...result
|
|
102
|
+
message: `Move sent successfully. ${result.winner ? result.winner + ' wins. ' + result.loser + ' loses.' : "It's a tie."}`,
|
|
103
|
+
...result,
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -110,7 +110,9 @@ function playMove(params, games, sessions, u, now) {
|
|
|
110
110
|
// Update session
|
|
111
111
|
sessions[u] = sessions[u] || { user: session, last: now };
|
|
112
112
|
sessions[u].last = now;
|
|
113
|
-
setTimeout(() => {
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
if (now - sessions[u].last >= 3600000) delete sessions[u];
|
|
115
|
+
}, 3600000);
|
|
114
116
|
|
|
115
117
|
return { message: 'Move sent successfully' };
|
|
116
118
|
}
|
|
@@ -125,7 +127,7 @@ function fetchGame(params, games, u) {
|
|
|
125
127
|
moves: [],
|
|
126
128
|
players: [],
|
|
127
129
|
private: params.private || false,
|
|
128
|
-
creation: Date.now()
|
|
130
|
+
creation: Date.now(),
|
|
129
131
|
};
|
|
130
132
|
}
|
|
131
133
|
if (!games[id].players.includes(u)) {
|
|
@@ -136,7 +138,7 @@ function fetchGame(params, games, u) {
|
|
|
136
138
|
const players = games[id].players;
|
|
137
139
|
const privateGame = games[id].private;
|
|
138
140
|
const lastPlayer = moves.length ? moves[moves.length - 1].username : null;
|
|
139
|
-
const turn = players.find(p => p !== lastPlayer) || players[0];
|
|
141
|
+
const turn = players.find((p) => p !== lastPlayer) || players[0];
|
|
140
142
|
const status = players.length >= 2 ? 'ready' : 'waiting';
|
|
141
143
|
const result = moves.length ? checkGame(moves) : {};
|
|
142
144
|
|
|
@@ -147,7 +149,7 @@ function fetchGame(params, games, u) {
|
|
|
147
149
|
turn,
|
|
148
150
|
status,
|
|
149
151
|
private: privateGame,
|
|
150
|
-
...result
|
|
152
|
+
...result,
|
|
151
153
|
};
|
|
152
154
|
}
|
|
153
155
|
|
|
@@ -167,7 +169,7 @@ function listGames(games) {
|
|
|
167
169
|
// Only include active games (not finished)
|
|
168
170
|
if (!isFinished) {
|
|
169
171
|
const lastPlayer = game.moves.length ? game.moves[game.moves.length - 1].username : null;
|
|
170
|
-
const turn = game.players.find(p => p !== lastPlayer) || game.players[0];
|
|
172
|
+
const turn = game.players.find((p) => p !== lastPlayer) || game.players[0];
|
|
171
173
|
const status = game.players.length >= 2 ? 'ready' : 'waiting';
|
|
172
174
|
|
|
173
175
|
publicGames.push({
|
|
@@ -177,7 +179,7 @@ function listGames(games) {
|
|
|
177
179
|
moves: game.moves.length,
|
|
178
180
|
turn,
|
|
179
181
|
status,
|
|
180
|
-
creation: game.creation || now
|
|
182
|
+
creation: game.creation || now,
|
|
181
183
|
});
|
|
182
184
|
}
|
|
183
185
|
}
|
|
@@ -189,7 +191,7 @@ function listGames(games) {
|
|
|
189
191
|
return {
|
|
190
192
|
message: 'Public games available',
|
|
191
193
|
count: publicGames.length,
|
|
192
|
-
games: publicGames
|
|
194
|
+
games: publicGames,
|
|
193
195
|
};
|
|
194
196
|
}
|
|
195
197
|
|
|
@@ -198,14 +200,18 @@ function listGames(games) {
|
|
|
198
200
|
*/
|
|
199
201
|
function generateGameId() {
|
|
200
202
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
201
|
-
return Array.from(randomBytes(5))
|
|
203
|
+
return Array.from(randomBytes(5))
|
|
204
|
+
.map((b) => chars[b % chars.length])
|
|
205
|
+
.join('');
|
|
202
206
|
}
|
|
203
207
|
|
|
204
208
|
/**
|
|
205
209
|
* Check the game result
|
|
206
210
|
*/
|
|
207
211
|
function checkGame(moves) {
|
|
208
|
-
let board = Array(3)
|
|
212
|
+
let board = Array(3)
|
|
213
|
+
.fill()
|
|
214
|
+
.map(() => Array(3).fill(null));
|
|
209
215
|
let playerSymbols = {};
|
|
210
216
|
let playersOrder = [];
|
|
211
217
|
|
|
@@ -228,9 +234,9 @@ function checkGame(moves) {
|
|
|
228
234
|
return false;
|
|
229
235
|
};
|
|
230
236
|
|
|
231
|
-
let winner = Object.keys(playerSymbols).find(player => checkWinner(playerSymbols[player]));
|
|
237
|
+
let winner = Object.keys(playerSymbols).find((player) => checkWinner(playerSymbols[player]));
|
|
232
238
|
let isTie = !winner && moves.length === 9;
|
|
233
|
-
let loser = winner && playersOrder.length === 2 ? playersOrder.find(player => player !== winner) : null;
|
|
239
|
+
let loser = winner && playersOrder.length === 2 ? playersOrder.find((player) => player !== winner) : null;
|
|
234
240
|
|
|
235
241
|
return { winner, loser, tie: isTie };
|
|
236
|
-
}
|
|
242
|
+
}
|