@20syldev/api 4.8.0 → 5.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/README.md +93 -55
- package/dist/config/versions.js +16 -0
- package/dist/config/versions.js.map +1 -1
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -1
- package/dist/modules/v5/chart.js +379 -0
- package/dist/modules/v5/chart.js.map +1 -0
- package/dist/modules/v5/evaluate.js +281 -0
- package/dist/modules/v5/evaluate.js.map +1 -0
- package/dist/modules/v5/matrix.js +238 -0
- package/dist/modules/v5/matrix.js.map +1 -0
- package/dist/modules/v5.js +5 -0
- package/dist/modules/v5.js.map +1 -0
- package/dist/routes/get.js +191 -162
- package/dist/routes/get.js.map +1 -1
- package/dist/routes/post.js +69 -0
- package/dist/routes/post.js.map +1 -1
- package/package.json +4 -2
- package/recap.md +98 -0
- package/.github/FUNDING.yml +0 -1
- package/.prettierrc +0 -7
- package/eslint.config.js +0 -24
- package/robots.txt +0 -74
- package/src/app.ts +0 -53
- package/src/config/env.ts +0 -87
- package/src/config/plans.ts +0 -61
- package/src/config/versions.ts +0 -121
- package/src/constants.ts +0 -61
- package/src/favicon.ico +0 -0
- package/src/middleware/cors.ts +0 -23
- package/src/middleware/error.ts +0 -16
- package/src/middleware/json.ts +0 -9
- package/src/middleware/logger.ts +0 -32
- package/src/middleware/ratelimit.ts +0 -89
- package/src/middleware/version.ts +0 -40
- package/src/modules/v3/algorithms.js +0 -218
- package/src/modules/v3/captcha.js +0 -60
- package/src/modules/v3/chat.js +0 -111
- package/src/modules/v3/color.js +0 -60
- package/src/modules/v3/convert.js +0 -39
- package/src/modules/v3/domain.js +0 -86
- package/src/modules/v3/hash.js +0 -16
- package/src/modules/v3/hyperplanning.js +0 -56
- package/src/modules/v3/levenshtein.js +0 -46
- package/src/modules/v3/personal.js +0 -139
- package/src/modules/v3/qrcode.js +0 -20
- package/src/modules/v3/tic_tac_toe.js +0 -242
- package/src/modules/v3/time.js +0 -98
- package/src/modules/v3/token.js +0 -54
- package/src/modules/v3/username.js +0 -94
- package/src/modules/v3/utils.js +0 -77
- package/src/modules/v3.js +0 -15
- package/src/modules/v4/address.ts +0 -412
- package/src/modules/v4/agent.ts +0 -104
- package/src/modules/v4/algorithms.ts +0 -276
- package/src/modules/v4/captcha.ts +0 -114
- package/src/modules/v4/chat.ts +0 -130
- package/src/modules/v4/color.ts +0 -75
- package/src/modules/v4/convert.ts +0 -127
- package/src/modules/v4/cron.ts +0 -221
- package/src/modules/v4/dice.ts +0 -46
- package/src/modules/v4/domain.ts +0 -86
- package/src/modules/v4/encode.ts +0 -241
- package/src/modules/v4/geo.ts +0 -64
- package/src/modules/v4/hash.ts +0 -32
- package/src/modules/v4/hyperplanning.ts +0 -93
- package/src/modules/v4/ip.ts +0 -134
- package/src/modules/v4/levenshtein.ts +0 -46
- package/src/modules/v4/palette.ts +0 -71
- package/src/modules/v4/password.ts +0 -379
- package/src/modules/v4/personal.ts +0 -140
- package/src/modules/v4/placeholder.ts +0 -197
- package/src/modules/v4/qrcode.ts +0 -121
- package/src/modules/v4/regex.ts +0 -67
- package/src/modules/v4/statistics.ts +0 -62
- package/src/modules/v4/text.ts +0 -330
- package/src/modules/v4/tic_tac_toe.ts +0 -264
- package/src/modules/v4/time.ts +0 -149
- package/src/modules/v4/token.ts +0 -53
- package/src/modules/v4/username.ts +0 -94
- package/src/modules/v4/validate.ts +0 -76
- package/src/modules/v4.ts +0 -29
- package/src/routes/delete.ts +0 -72
- package/src/routes/get.ts +0 -856
- package/src/routes/index.ts +0 -59
- package/src/routes/patch.ts +0 -45
- package/src/routes/post.ts +0 -209
- package/src/storage/index.ts +0 -16
- package/src/types/express.d.ts +0 -17
- package/src/types/storage.ts +0 -48
- package/src/utils/colors.ts +0 -91
- package/src/utils/helpers.ts +0 -90
- package/src/utils/response.ts +0 -28
- package/tests/integration/api.test.ts +0 -772
- package/tests/tsconfig.json +0 -3
- package/tests/unit/address.test.ts +0 -84
- package/tests/unit/agent.test.ts +0 -113
- package/tests/unit/algorithms.test.ts +0 -121
- package/tests/unit/captcha.test.ts +0 -62
- package/tests/unit/chat.test.ts +0 -54
- package/tests/unit/color.test.ts +0 -54
- package/tests/unit/convert.test.ts +0 -68
- package/tests/unit/cron.test.ts +0 -110
- package/tests/unit/dice.test.ts +0 -58
- package/tests/unit/domain.test.ts +0 -48
- package/tests/unit/encode.test.ts +0 -109
- package/tests/unit/geo.test.ts +0 -46
- package/tests/unit/hash.test.ts +0 -45
- package/tests/unit/hyperplanning.test.ts +0 -97
- package/tests/unit/ip.test.ts +0 -140
- package/tests/unit/levenshtein.test.ts +0 -35
- package/tests/unit/palette.test.ts +0 -54
- package/tests/unit/password.test.ts +0 -86
- package/tests/unit/personal.test.ts +0 -66
- package/tests/unit/placeholder.test.ts +0 -58
- package/tests/unit/qrcode.test.ts +0 -83
- package/tests/unit/regex.test.ts +0 -95
- package/tests/unit/statistics.test.ts +0 -58
- package/tests/unit/text.test.ts +0 -108
- package/tests/unit/tic_tac_toe.test.ts +0 -56
- package/tests/unit/time.test.ts +0 -115
- package/tests/unit/token.test.ts +0 -62
- package/tests/unit/username.test.ts +0 -35
- package/tests/unit/validate.test.ts +0 -72
- package/tsconfig.json +0 -17
- package/tsconfig.test.json +0 -9
package/src/modules/v4/time.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { MAX_COUNTDOWN_YEARS } from '../../constants.js';
|
|
2
|
-
|
|
3
|
-
const VALID_FORMATS = [
|
|
4
|
-
'iso',
|
|
5
|
-
'utc',
|
|
6
|
-
'timestamp',
|
|
7
|
-
'locale',
|
|
8
|
-
'date',
|
|
9
|
-
'time',
|
|
10
|
-
'year',
|
|
11
|
-
'month',
|
|
12
|
-
'day',
|
|
13
|
-
'hour',
|
|
14
|
-
'minute',
|
|
15
|
-
'second',
|
|
16
|
-
'ms',
|
|
17
|
-
'dayOfWeek',
|
|
18
|
-
'dayOfYear',
|
|
19
|
-
'weekNumber',
|
|
20
|
-
'timezone',
|
|
21
|
-
'timezoneOffset',
|
|
22
|
-
] as const;
|
|
23
|
-
|
|
24
|
-
export const VALID_TIMEZONES = ['UTC', 'America/New_York', 'Europe/Paris', 'Asia/Tokyo', 'Australia/Sydney'] as const;
|
|
25
|
-
|
|
26
|
-
type TimeFormat = (typeof VALID_FORMATS)[number];
|
|
27
|
-
type Timezone = (typeof VALID_TIMEZONES)[number];
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Returns the current or a random date/time in various formats and timezones,
|
|
31
|
-
* or computes a countdown/elapsed time to/from a target date.
|
|
32
|
-
*
|
|
33
|
-
* @param type - "live" for the current time, "random" for a random date, or "countdown" for a time diff
|
|
34
|
-
* @param start - Optional start date for random mode (YYYY-MM-DD)
|
|
35
|
-
* @param end - Optional end date for random mode (YYYY-MM-DD)
|
|
36
|
-
* @param format - Optional specific format to return (e.g. "iso", "timestamp", "year")
|
|
37
|
-
* @param timezone - Optional timezone (e.g. "UTC", "Europe/Paris")
|
|
38
|
-
* @param target - Required for countdown mode: target date in ISO 8601 or YYYY-MM-DD format
|
|
39
|
-
* @returns Object containing all time formats, a single format, or a countdown result
|
|
40
|
-
* @throws Error if type, format, timezone, or target is invalid
|
|
41
|
-
*/
|
|
42
|
-
export default function time(
|
|
43
|
-
type: string = 'live',
|
|
44
|
-
start?: string,
|
|
45
|
-
end?: string,
|
|
46
|
-
format?: string,
|
|
47
|
-
timezone?: string,
|
|
48
|
-
target?: string,
|
|
49
|
-
): Record<string, unknown> {
|
|
50
|
-
if (type !== 'live' && type !== 'random' && type !== 'countdown') {
|
|
51
|
-
throw new Error('Please provide a valid type (live, random or countdown)');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (timezone && !VALID_TIMEZONES.includes(timezone as Timezone)) {
|
|
55
|
-
throw new Error(`Please provide a valid timezone. Options: ${VALID_TIMEZONES.join(', ')}`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (type === 'countdown') {
|
|
59
|
-
if (!target) {
|
|
60
|
-
throw new Error('Please provide a target date (?target=YYYY-MM-DD)');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const targetDate = new Date(target);
|
|
64
|
-
if (isNaN(targetDate.getTime())) {
|
|
65
|
-
throw new Error('Please provide a valid target date (ISO 8601 or YYYY-MM-DD)');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const now = new Date();
|
|
69
|
-
const maxMs = MAX_COUNTDOWN_YEARS * 365.25 * 24 * 3600 * 1000;
|
|
70
|
-
|
|
71
|
-
if (Math.abs(targetDate.getTime() - now.getTime()) > maxMs) {
|
|
72
|
-
throw new Error(`Target date must be within ${MAX_COUNTDOWN_YEARS} years from now`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const direction: 'future' | 'past' = targetDate > now ? 'future' : 'past';
|
|
76
|
-
const diffMs = Math.abs(targetDate.getTime() - now.getTime());
|
|
77
|
-
const total_seconds = Math.floor(diffMs / 1000);
|
|
78
|
-
|
|
79
|
-
const days = Math.floor(total_seconds / 86400);
|
|
80
|
-
const hours = Math.floor((total_seconds % 86400) / 3600);
|
|
81
|
-
const minutes = Math.floor((total_seconds % 3600) / 60);
|
|
82
|
-
const seconds = total_seconds % 60;
|
|
83
|
-
|
|
84
|
-
const parts: string[] = [];
|
|
85
|
-
if (days > 0) parts.push(`${days} day${days !== 1 ? 's' : ''}`);
|
|
86
|
-
if (hours > 0) parts.push(`${hours} hour${hours !== 1 ? 's' : ''}`);
|
|
87
|
-
if (minutes > 0) parts.push(`${minutes} minute${minutes !== 1 ? 's' : ''}`);
|
|
88
|
-
if (seconds > 0) parts.push(`${seconds} second${seconds !== 1 ? 's' : ''}`);
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
target: targetDate.toISOString(),
|
|
92
|
-
now: now.toISOString(),
|
|
93
|
-
direction,
|
|
94
|
-
remaining: { total_seconds, days, hours, minutes, seconds },
|
|
95
|
-
human: parts.length > 0 ? parts.join(', ') : '0 seconds',
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (start && !Date.parse(start)) {
|
|
100
|
-
throw new Error('Please provide a valid start date (YYYY-MM-DD)');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (end && !Date.parse(end)) {
|
|
104
|
-
throw new Error('Please provide a valid end date (YYYY-MM-DD)');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (format && !VALID_FORMATS.includes(format as TimeFormat)) {
|
|
108
|
-
throw new Error(`Please provide a valid format. Options: ${VALID_FORMATS.join(', ')}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const getTimeFormats = (date: Date, tz: string): Record<string, unknown> => {
|
|
112
|
-
return {
|
|
113
|
-
iso: date.toISOString(),
|
|
114
|
-
utc: date.toUTCString(),
|
|
115
|
-
timestamp: date.getTime(),
|
|
116
|
-
locale: date.toLocaleString('en-US', { timeZone: tz, timeZoneName: 'long' }),
|
|
117
|
-
date: date.toLocaleDateString('en-US', { timeZone: tz }),
|
|
118
|
-
time: date.toLocaleTimeString('en-US', { timeZone: tz }),
|
|
119
|
-
year: date.getFullYear(),
|
|
120
|
-
month: date.getMonth() + 1,
|
|
121
|
-
day: date.getDate(),
|
|
122
|
-
hour: date.getHours(),
|
|
123
|
-
minute: date.getMinutes(),
|
|
124
|
-
second: date.getSeconds(),
|
|
125
|
-
ms: date.getMilliseconds(),
|
|
126
|
-
dayOfWeek: date.getDay(),
|
|
127
|
-
dayOfYear: Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000),
|
|
128
|
-
weekNumber: Math.ceil(((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000 + 1) / 7),
|
|
129
|
-
timezone: tz,
|
|
130
|
-
timezoneOffset: date.getTimezoneOffset(),
|
|
131
|
-
};
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
if (type === 'random') {
|
|
135
|
-
const startDate = start ? new Date(start).getTime() : new Date('1900-01-01').getTime();
|
|
136
|
-
const endDate = end ? new Date(end).getTime() : new Date('2100-12-31').getTime();
|
|
137
|
-
const randomDate = new Date(startDate + Math.random() * (endDate - startDate));
|
|
138
|
-
const tz = timezone || VALID_TIMEZONES[Math.floor(Math.random() * VALID_TIMEZONES.length)]!;
|
|
139
|
-
const formats = getTimeFormats(randomDate, tz);
|
|
140
|
-
|
|
141
|
-
return format ? { date: formats[format] } : formats;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const now = new Date();
|
|
145
|
-
const tz = timezone || 'UTC';
|
|
146
|
-
const formats = getTimeFormats(now, tz);
|
|
147
|
-
|
|
148
|
-
return format ? { date: formats[format] } : formats;
|
|
149
|
-
}
|
package/src/modules/v4/token.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { randomBytes, randomInt } from 'crypto';
|
|
2
|
-
import { v4 } from 'uuid';
|
|
3
|
-
|
|
4
|
-
import { MAX_TOKEN_LENGTH, MIN_TOKEN_LENGTH } from '../../constants.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Generates a cryptographically random token of the specified length and type.
|
|
8
|
-
*
|
|
9
|
-
* @param len - Token length (must be between 12 and 4096)
|
|
10
|
-
* @param type - Character set to use: "alpha", "alphanum", "base64", "hex", "num", "punct", "urlsafe", or "uuid"
|
|
11
|
-
* @returns The generated token string
|
|
12
|
-
* @throws Error if length is out of range or the type is not valid
|
|
13
|
-
*/
|
|
14
|
-
export default function token(len: number, type: string = 'alphanum'): string {
|
|
15
|
-
if (isNaN(len) || len < MIN_TOKEN_LENGTH) {
|
|
16
|
-
throw new Error('Length must be a number greater than or equal to 12');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (len > MAX_TOKEN_LENGTH) {
|
|
20
|
-
throw new Error('Length cannot exceed 4096');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const genToken = (chars: string, length: number): string =>
|
|
24
|
-
Array.from({ length }, () => chars[randomInt(chars.length)]).join('');
|
|
25
|
-
|
|
26
|
-
const tokenTypes: Record<string, () => string> = {
|
|
27
|
-
alpha: () => genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', len),
|
|
28
|
-
alphanum: () => genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', len),
|
|
29
|
-
base64: () =>
|
|
30
|
-
randomBytes(Math.ceil(len * 0.75))
|
|
31
|
-
.toString('base64')
|
|
32
|
-
.slice(0, len),
|
|
33
|
-
hex: () =>
|
|
34
|
-
randomBytes(Math.ceil(len * 0.5))
|
|
35
|
-
.toString('hex')
|
|
36
|
-
.slice(0, len),
|
|
37
|
-
num: () => genToken('0123456789', len),
|
|
38
|
-
punct: () => genToken('!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~', len),
|
|
39
|
-
urlsafe: () => genToken('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_', len),
|
|
40
|
-
uuid: () => {
|
|
41
|
-
let result = '';
|
|
42
|
-
while (result.length < len) result += v4().replace(/-/g, '');
|
|
43
|
-
return result.slice(0, len);
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const lowerType = type.toLowerCase();
|
|
48
|
-
if (!tokenTypes[lowerType]) {
|
|
49
|
-
throw new Error(`Invalid token type. Valid types: ${Object.keys(tokenTypes).join(', ')}`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return tokenTypes[lowerType]!();
|
|
53
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { random, randomNumber } from '../../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates a random username combining adjectives, animals, and job titles.
|
|
5
|
-
*
|
|
6
|
-
* @returns Object containing the generated username, the number used, and the components (adjective, animal, job)
|
|
7
|
-
*/
|
|
8
|
-
export default function username(): Record<string, unknown> {
|
|
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: Record<string, () => string> = {
|
|
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
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { MAX_STRING_LENGTH } from '../../constants.js';
|
|
2
|
-
|
|
3
|
-
function checkValue(value: string): void {
|
|
4
|
-
if (!value) throw new Error('A value is required');
|
|
5
|
-
if (typeof value !== 'string') throw new Error('Value must be a string');
|
|
6
|
-
if (value.length > MAX_STRING_LENGTH)
|
|
7
|
-
throw new Error(`Value must be less than ${MAX_STRING_LENGTH} characters long`);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Validates a credit/debit card number using the Luhn algorithm.
|
|
12
|
-
*
|
|
13
|
-
* @param value - Card number string (digits, spaces, or dashes allowed)
|
|
14
|
-
* @returns Object containing the validity result and the sanitized digit string
|
|
15
|
-
* @throws Error if value is missing, contains non-digit characters, or has an invalid length
|
|
16
|
-
*/
|
|
17
|
-
export function luhn(value: string): { valid: boolean; value: string } {
|
|
18
|
-
checkValue(value);
|
|
19
|
-
const digits = value.replace(/\s|-/g, '');
|
|
20
|
-
if (!/^\d+$/.test(digits)) throw new Error('Value must contain only digits, spaces or dashes');
|
|
21
|
-
if (digits.length < 12 || digits.length > 19) throw new Error('Card number must have between 12 and 19 digits');
|
|
22
|
-
|
|
23
|
-
let sum = 0;
|
|
24
|
-
let alt = false;
|
|
25
|
-
for (let i = digits.length - 1; i >= 0; i--) {
|
|
26
|
-
let n = parseInt(digits[i]!, 10);
|
|
27
|
-
if (alt) {
|
|
28
|
-
n *= 2;
|
|
29
|
-
if (n > 9) n -= 9;
|
|
30
|
-
}
|
|
31
|
-
sum += n;
|
|
32
|
-
alt = !alt;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return { valid: sum % 10 === 0, value: digits };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Validates an IBAN using the mod-97 checksum algorithm.
|
|
40
|
-
*
|
|
41
|
-
* @param value - IBAN string (spaces allowed)
|
|
42
|
-
* @returns Object containing the validity result, sanitized IBAN, and country code
|
|
43
|
-
* @throws Error if value is missing, has an invalid format, or is out of length bounds
|
|
44
|
-
*/
|
|
45
|
-
export function iban(value: string): { valid: boolean; value: string; country?: string } {
|
|
46
|
-
checkValue(value);
|
|
47
|
-
const cleaned = value.replace(/\s/g, '').toUpperCase();
|
|
48
|
-
if (!/^[A-Z]{2}\d{2}[A-Z0-9]+$/.test(cleaned)) throw new Error('Invalid IBAN format');
|
|
49
|
-
if (cleaned.length < 15 || cleaned.length > 34) throw new Error('IBAN length must be between 15 and 34 characters');
|
|
50
|
-
|
|
51
|
-
const rearranged = cleaned.slice(4) + cleaned.slice(0, 4);
|
|
52
|
-
const numeric = rearranged
|
|
53
|
-
.split('')
|
|
54
|
-
.map((c) => (c >= 'A' && c <= 'Z' ? (c.charCodeAt(0) - 55).toString() : c))
|
|
55
|
-
.join('');
|
|
56
|
-
|
|
57
|
-
let remainder = 0;
|
|
58
|
-
for (const char of numeric) {
|
|
59
|
-
remainder = (remainder * 10 + parseInt(char, 10)) % 97;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return { valid: remainder === 1, value: cleaned, country: cleaned.slice(0, 2) };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Validates an email address against a basic format check.
|
|
67
|
-
*
|
|
68
|
-
* @param value - The email address string to validate
|
|
69
|
-
* @returns Object containing the validity result and the original value
|
|
70
|
-
* @throws Error if value is missing, not a string, or too long
|
|
71
|
-
*/
|
|
72
|
-
export function email(value: string): { valid: boolean; value: string } {
|
|
73
|
-
checkValue(value);
|
|
74
|
-
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
75
|
-
return { valid: regex.test(value), value };
|
|
76
|
-
}
|
package/src/modules/v4.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export { default as address } from './v4/address.js';
|
|
2
|
-
export { default as agent } from './v4/agent.js';
|
|
3
|
-
export * as algorithms from './v4/algorithms.js';
|
|
4
|
-
export { default as captcha } from './v4/captcha.js';
|
|
5
|
-
export { default as chat } from './v4/chat.js';
|
|
6
|
-
export { default as color } from './v4/color.js';
|
|
7
|
-
export { default as convert } from './v4/convert.js';
|
|
8
|
-
export { default as cron } from './v4/cron.js';
|
|
9
|
-
export { default as dice } from './v4/dice.js';
|
|
10
|
-
export { default as domain } from './v4/domain.js';
|
|
11
|
-
export * as encode from './v4/encode.js';
|
|
12
|
-
export { default as geo } from './v4/geo.js';
|
|
13
|
-
export { default as hash } from './v4/hash.js';
|
|
14
|
-
export { default as hyperplanning } from './v4/hyperplanning.js';
|
|
15
|
-
export { default as ip } from './v4/ip.js';
|
|
16
|
-
export { default as levenshtein } from './v4/levenshtein.js';
|
|
17
|
-
export { default as palette } from './v4/palette.js';
|
|
18
|
-
export { default as password } from './v4/password.js';
|
|
19
|
-
export { default as personal } from './v4/personal.js';
|
|
20
|
-
export { default as placeholder } from './v4/placeholder.js';
|
|
21
|
-
export { default as qrcode } from './v4/qrcode.js';
|
|
22
|
-
export { default as regex } from './v4/regex.js';
|
|
23
|
-
export { default as statistics } from './v4/statistics.js';
|
|
24
|
-
export * as text from './v4/text.js';
|
|
25
|
-
export { default as tic_tac_toe } from './v4/tic_tac_toe.js';
|
|
26
|
-
export { default as time } from './v4/time.js';
|
|
27
|
-
export { default as token } from './v4/token.js';
|
|
28
|
-
export { default as username } from './v4/username.js';
|
|
29
|
-
export * as validate from './v4/validate.js';
|
package/src/routes/delete.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { type Request, type Response, Router } from 'express';
|
|
2
|
-
|
|
3
|
-
import { chatStorage, ticTacToeStorage } from '../storage/index.js';
|
|
4
|
-
import { error } from '../utils/response.js';
|
|
5
|
-
|
|
6
|
-
const router = Router();
|
|
7
|
-
|
|
8
|
-
// Clear a private chat
|
|
9
|
-
router.delete('/:version/chat/:token', (req: Request, res: Response) => {
|
|
10
|
-
if (req.version !== 'v4') {
|
|
11
|
-
error(res, 405, 'DELETE is only supported in v4+.', `${req.version}/chat`);
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const token = req.params.token as string;
|
|
16
|
-
const { username, session } = (req.body as Record<string, string>) || {};
|
|
17
|
-
|
|
18
|
-
if (!username) {
|
|
19
|
-
error(res, 400, 'Please provide a username (?username={username})');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
if (!session) {
|
|
23
|
-
error(res, 400, 'Please provide a valid session ID (&session={ID})');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
const result = req.module.chat('clear', {
|
|
29
|
-
username,
|
|
30
|
-
token,
|
|
31
|
-
session,
|
|
32
|
-
storage: chatStorage,
|
|
33
|
-
});
|
|
34
|
-
res.jsonResponse(result);
|
|
35
|
-
} catch (err) {
|
|
36
|
-
error(res, 400, (err as Error).message);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Forfeit a tic-tac-toe game
|
|
41
|
-
router.delete('/:version/tic-tac-toe/:game', (req: Request, res: Response) => {
|
|
42
|
-
if (req.version !== 'v4') {
|
|
43
|
-
error(res, 405, 'DELETE is only supported in v4+.', `${req.version}/tic-tac-toe`);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const game = req.params.game as string;
|
|
48
|
-
const { username, session } = (req.body as Record<string, string>) || {};
|
|
49
|
-
|
|
50
|
-
if (!username) {
|
|
51
|
-
error(res, 400, 'Please provide a username (?username={username})');
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
if (!session) {
|
|
55
|
-
error(res, 400, 'Please provide a valid session ID (&session={ID})');
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
const result = req.module.tic_tac_toe('forfeit', {
|
|
61
|
-
username,
|
|
62
|
-
session,
|
|
63
|
-
game,
|
|
64
|
-
storage: ticTacToeStorage,
|
|
65
|
-
});
|
|
66
|
-
res.jsonResponse(result);
|
|
67
|
-
} catch (err) {
|
|
68
|
-
error(res, 400, (err as Error).message);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
export default router;
|