@20syldev/api 3.5.0 → 4.1.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/docs/changelog.md +333 -0
- package/eslint.config.js +20 -0
- package/package.json +31 -15
- package/src/app.ts +48 -0
- package/src/config/env.ts +81 -0
- package/src/config/versions.ts +92 -0
- package/src/constants.ts +47 -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 +197 -0
- package/src/modules/v4/captcha.ts +49 -0
- package/src/modules/v4/chat.ts +122 -0
- package/src/modules/v4/color.ts +64 -0
- package/src/modules/v4/convert.ts +38 -0
- package/src/modules/v4/dice.ts +39 -0
- package/src/modules/v4/domain.ts +81 -0
- package/src/modules/v4/encode.ts +170 -0
- package/src/modules/v4/geo.ts +53 -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/palette.ts +103 -0
- package/src/modules/v4/personal.ts +147 -0
- package/src/modules/v4/placeholder.ts +122 -0
- package/src/modules/v4/qrcode.ts +11 -0
- package/src/modules/v4/statistics.ts +55 -0
- package/src/modules/v4/text.ts +300 -0
- package/src/modules/v4/tic_tac_toe.ts +255 -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/validate.ts +55 -0
- package/src/modules/v4.ts +17 -0
- package/src/routes/delete.ts +72 -0
- package/src/routes/get.ts +508 -0
- package/src/routes/index.ts +58 -0
- package/src/routes/patch.ts +45 -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/src/utils/version.ts +5 -0
- package/tests/integration/api.test.ts +395 -0
- package/tests/tsconfig.json +3 -0
- package/tests/unit/algorithms.test.ts +120 -0
- package/tests/unit/color.test.ts +33 -0
- package/tests/unit/convert.test.ts +42 -0
- package/tests/unit/dice.test.ts +57 -0
- package/tests/unit/domain.test.ts +47 -0
- package/tests/unit/encode.test.ts +108 -0
- package/tests/unit/geo.test.ts +45 -0
- package/tests/unit/hash.test.ts +37 -0
- package/tests/unit/hyperplanning.test.ts +77 -0
- package/tests/unit/levenshtein.test.ts +34 -0
- package/tests/unit/palette.test.ts +53 -0
- package/tests/unit/personal.test.ts +65 -0
- package/tests/unit/statistics.test.ts +57 -0
- package/tests/unit/text.test.ts +107 -0
- package/tests/unit/time.test.ts +67 -0
- package/tests/unit/token.test.ts +61 -0
- package/tests/unit/username.test.ts +34 -0
- package/tests/unit/validate.test.ts +71 -0
- package/tsconfig.json +17 -0
- package/tsconfig.test.json +9 -0
- package/app.js +0 -865
- package/modules/v3/username.js +0 -32
|
@@ -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
|
+
}
|
|
@@ -11,16 +11,27 @@
|
|
|
11
11
|
*/
|
|
12
12
|
export default function time(type = 'live', start, end, format, timezone) {
|
|
13
13
|
const validFormats = [
|
|
14
|
-
'iso',
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'
|
|
14
|
+
'iso',
|
|
15
|
+
'utc',
|
|
16
|
+
'timestamp',
|
|
17
|
+
'locale',
|
|
18
|
+
'date',
|
|
19
|
+
'time',
|
|
20
|
+
'year',
|
|
21
|
+
'month',
|
|
22
|
+
'day',
|
|
23
|
+
'hour',
|
|
24
|
+
'minute',
|
|
25
|
+
'second',
|
|
26
|
+
'ms',
|
|
27
|
+
'dayOfWeek',
|
|
28
|
+
'dayOfYear',
|
|
29
|
+
'weekNumber',
|
|
30
|
+
'timezone',
|
|
31
|
+
'timezoneOffset',
|
|
18
32
|
];
|
|
19
33
|
|
|
20
|
-
const validTimezones = [
|
|
21
|
-
'UTC', 'America/New_York', 'Europe/Paris',
|
|
22
|
-
'Asia/Tokyo', 'Australia/Sydney'
|
|
23
|
-
];
|
|
34
|
+
const validTimezones = ['UTC', 'America/New_York', 'Europe/Paris', 'Asia/Tokyo', 'Australia/Sydney'];
|
|
24
35
|
|
|
25
36
|
// Input validation
|
|
26
37
|
if (type !== 'live' && type !== 'random') {
|
|
@@ -61,9 +72,9 @@ export default function time(type = 'live', start, end, format, timezone) {
|
|
|
61
72
|
ms: date.getMilliseconds(),
|
|
62
73
|
dayOfWeek: date.getDay(),
|
|
63
74
|
dayOfYear: Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 86400000),
|
|
64
|
-
weekNumber: Math.ceil(((
|
|
75
|
+
weekNumber: Math.ceil(((date - new Date(date.getFullYear(), 0, 0)) / 86400000 + 1) / 7),
|
|
65
76
|
timezone: tz,
|
|
66
|
-
timezoneOffset: date.getTimezoneOffset()
|
|
77
|
+
timezoneOffset: date.getTimezoneOffset(),
|
|
67
78
|
};
|
|
68
79
|
};
|
|
69
80
|
|
|
@@ -84,4 +95,4 @@ export default function time(type = 'live', start, end, format, timezone) {
|
|
|
84
95
|
const formats = getTimeFormats(now, tz);
|
|
85
96
|
|
|
86
97
|
return format ? { date: formats[format] } : formats;
|
|
87
|
-
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
2
|
+
import { v4 } from 'uuid';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generate a random token of specified length and type.
|
|
6
|
+
*
|
|
7
|
+
* @param {number} len - Length of the token
|
|
8
|
+
* @param {string} type - Type of token to generate
|
|
9
|
+
* @returns {string} - The generated token
|
|
10
|
+
* @throws {Error} - If inputs are invalid
|
|
11
|
+
*/
|
|
12
|
+
export default function token(len, type = 'alphanum') {
|
|
13
|
+
// Input validation
|
|
14
|
+
if (isNaN(len) || len < 12) {
|
|
15
|
+
throw new Error('Length must be a number greater than or equal to 12');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (len > 4096) {
|
|
19
|
+
throw new Error('Length cannot exceed 4096');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Helper function to generate token from character set
|
|
23
|
+
const genToken = (chars, length) => {
|
|
24
|
+
return Array.from({ length }, () => {
|
|
25
|
+
return chars[Math.floor(Math.random() * chars.length)];
|
|
26
|
+
}).join('');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Token type definitions
|
|
30
|
+
const tokenTypes = {
|
|
31
|
+
alpha: () => genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', len),
|
|
32
|
+
alphanum: () => genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', len),
|
|
33
|
+
base64: () =>
|
|
34
|
+
randomBytes(Math.ceil(len * 0.75))
|
|
35
|
+
.toString('base64')
|
|
36
|
+
.slice(0, len),
|
|
37
|
+
hex: () =>
|
|
38
|
+
randomBytes(Math.ceil(len * 0.5))
|
|
39
|
+
.toString('hex')
|
|
40
|
+
.slice(0, len),
|
|
41
|
+
num: () => genToken('0123456789', len),
|
|
42
|
+
punct: () => genToken('!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~', len),
|
|
43
|
+
urlsafe: () => genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_', len),
|
|
44
|
+
uuid: () => v4().replace(/-/g, '').slice(0, len),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Generate token based on type or default to alphanum
|
|
48
|
+
if (!tokenTypes[type.toLowerCase()]) {
|
|
49
|
+
throw new Error(`Invalid token type. Valid types: ${Object.keys(tokenTypes).join(', ')}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Generate token based on type or default to alphanum
|
|
53
|
+
return (tokenTypes[type.toLowerCase()] || tokenTypes.alphanum)();
|
|
54
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { random, randomNumber } from './utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a random username with related information
|
|
5
|
+
*
|
|
6
|
+
* @returns {Object} Object containing username and component parts
|
|
7
|
+
*/
|
|
8
|
+
export default function username() {
|
|
9
|
+
const adj = [
|
|
10
|
+
'Happy',
|
|
11
|
+
'Silly',
|
|
12
|
+
'Clever',
|
|
13
|
+
'Creative',
|
|
14
|
+
'Brave',
|
|
15
|
+
'Gentle',
|
|
16
|
+
'Kind',
|
|
17
|
+
'Funny',
|
|
18
|
+
'Wise',
|
|
19
|
+
'Charming',
|
|
20
|
+
'Sincere',
|
|
21
|
+
'Resourceful',
|
|
22
|
+
'Patient',
|
|
23
|
+
'Energetic',
|
|
24
|
+
'Adventurous',
|
|
25
|
+
'Ambitious',
|
|
26
|
+
'Courageous',
|
|
27
|
+
'Courteous',
|
|
28
|
+
'Determined',
|
|
29
|
+
];
|
|
30
|
+
const ani = [
|
|
31
|
+
'Cat',
|
|
32
|
+
'Dog',
|
|
33
|
+
'Tiger',
|
|
34
|
+
'Elephant',
|
|
35
|
+
'Monkey',
|
|
36
|
+
'Penguin',
|
|
37
|
+
'Dolphin',
|
|
38
|
+
'Lion',
|
|
39
|
+
'Bear',
|
|
40
|
+
'Fox',
|
|
41
|
+
'Owl',
|
|
42
|
+
'Giraffe',
|
|
43
|
+
'Zebra',
|
|
44
|
+
'Koala',
|
|
45
|
+
'Rabbit',
|
|
46
|
+
'Squirrel',
|
|
47
|
+
'Panda',
|
|
48
|
+
'Horse',
|
|
49
|
+
'Wolf',
|
|
50
|
+
'Eagle',
|
|
51
|
+
];
|
|
52
|
+
const job = [
|
|
53
|
+
'Writer',
|
|
54
|
+
'Artist',
|
|
55
|
+
'Musician',
|
|
56
|
+
'Explorer',
|
|
57
|
+
'Scientist',
|
|
58
|
+
'Engineer',
|
|
59
|
+
'Athlete',
|
|
60
|
+
'Chef',
|
|
61
|
+
'Doctor',
|
|
62
|
+
'Teacher',
|
|
63
|
+
'Lawyer',
|
|
64
|
+
'Entrepreneur',
|
|
65
|
+
'Actor',
|
|
66
|
+
'Dancer',
|
|
67
|
+
'Photographer',
|
|
68
|
+
'Architect',
|
|
69
|
+
'Pilot',
|
|
70
|
+
'Designer',
|
|
71
|
+
'Journalist',
|
|
72
|
+
'Veterinarian',
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const nombre = randomNumber(0, 99);
|
|
76
|
+
const choix = {
|
|
77
|
+
adj_num: () => random(adj) + nombre,
|
|
78
|
+
ani_num: () => random(ani) + nombre,
|
|
79
|
+
pro_num: () => random(job) + nombre,
|
|
80
|
+
adj_ani: () => random(adj) + random(ani),
|
|
81
|
+
adj_ani_num: () => random(adj) + random(ani) + nombre,
|
|
82
|
+
adj_pro: () => random(adj) + random(job),
|
|
83
|
+
pro_ani: () => random(job) + random(ani),
|
|
84
|
+
pro_ani_num: () => random(job) + random(ani) + nombre,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
username: choix[random(Object.keys(choix))](),
|
|
89
|
+
number: nombre,
|
|
90
|
+
adjective: random(adj),
|
|
91
|
+
animal: random(ani),
|
|
92
|
+
job: random(job),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -65,7 +65,7 @@ export function envList(key) {
|
|
|
65
65
|
* @throws {Error} - If rate limit is exceeded
|
|
66
66
|
*/
|
|
67
67
|
export function checkRateLimit(rateLimits, userId, timestamp, window = 10000, limit = 50) {
|
|
68
|
-
rateLimits[userId] = (rateLimits[userId] || []).filter(ts => timestamp - ts < window);
|
|
68
|
+
rateLimits[userId] = (rateLimits[userId] || []).filter((ts) => timestamp - ts < window);
|
|
69
69
|
|
|
70
70
|
if (rateLimits[userId].length > limit) {
|
|
71
71
|
const remainingTime = Math.ceil((rateLimits[userId][0] + window - timestamp) / 1000);
|
|
@@ -74,4 +74,4 @@ export function checkRateLimit(rateLimits, userId, timestamp, window = 10000, li
|
|
|
74
74
|
|
|
75
75
|
rateLimits[userId].push(timestamp);
|
|
76
76
|
return false;
|
|
77
|
-
}
|
|
77
|
+
}
|
|
@@ -12,4 +12,4 @@ export { default as qrcode } from './v3/qrcode.js';
|
|
|
12
12
|
export { default as tic_tac_toe } from './v3/tic_tac_toe.js';
|
|
13
13
|
export { default as time } from './v3/time.js';
|
|
14
14
|
export { default as token } from './v3/token.js';
|
|
15
|
-
export { default as username } from './v3/username.js';
|
|
15
|
+
export { default as username } from './v3/username.js';
|