@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.
Files changed (126) hide show
  1. package/README.md +93 -55
  2. package/dist/config/versions.js +16 -0
  3. package/dist/config/versions.js.map +1 -1
  4. package/dist/constants.js +5 -0
  5. package/dist/constants.js.map +1 -1
  6. package/dist/modules/v5/chart.js +379 -0
  7. package/dist/modules/v5/chart.js.map +1 -0
  8. package/dist/modules/v5/evaluate.js +281 -0
  9. package/dist/modules/v5/evaluate.js.map +1 -0
  10. package/dist/modules/v5/matrix.js +238 -0
  11. package/dist/modules/v5/matrix.js.map +1 -0
  12. package/dist/modules/v5.js +5 -0
  13. package/dist/modules/v5.js.map +1 -0
  14. package/dist/routes/get.js +191 -162
  15. package/dist/routes/get.js.map +1 -1
  16. package/dist/routes/post.js +69 -0
  17. package/dist/routes/post.js.map +1 -1
  18. package/package.json +4 -2
  19. package/recap.md +98 -0
  20. package/.github/FUNDING.yml +0 -1
  21. package/.prettierrc +0 -7
  22. package/eslint.config.js +0 -24
  23. package/robots.txt +0 -74
  24. package/src/app.ts +0 -53
  25. package/src/config/env.ts +0 -87
  26. package/src/config/plans.ts +0 -61
  27. package/src/config/versions.ts +0 -121
  28. package/src/constants.ts +0 -61
  29. package/src/favicon.ico +0 -0
  30. package/src/middleware/cors.ts +0 -23
  31. package/src/middleware/error.ts +0 -16
  32. package/src/middleware/json.ts +0 -9
  33. package/src/middleware/logger.ts +0 -32
  34. package/src/middleware/ratelimit.ts +0 -89
  35. package/src/middleware/version.ts +0 -40
  36. package/src/modules/v3/algorithms.js +0 -218
  37. package/src/modules/v3/captcha.js +0 -60
  38. package/src/modules/v3/chat.js +0 -111
  39. package/src/modules/v3/color.js +0 -60
  40. package/src/modules/v3/convert.js +0 -39
  41. package/src/modules/v3/domain.js +0 -86
  42. package/src/modules/v3/hash.js +0 -16
  43. package/src/modules/v3/hyperplanning.js +0 -56
  44. package/src/modules/v3/levenshtein.js +0 -46
  45. package/src/modules/v3/personal.js +0 -139
  46. package/src/modules/v3/qrcode.js +0 -20
  47. package/src/modules/v3/tic_tac_toe.js +0 -242
  48. package/src/modules/v3/time.js +0 -98
  49. package/src/modules/v3/token.js +0 -54
  50. package/src/modules/v3/username.js +0 -94
  51. package/src/modules/v3/utils.js +0 -77
  52. package/src/modules/v3.js +0 -15
  53. package/src/modules/v4/address.ts +0 -412
  54. package/src/modules/v4/agent.ts +0 -104
  55. package/src/modules/v4/algorithms.ts +0 -276
  56. package/src/modules/v4/captcha.ts +0 -114
  57. package/src/modules/v4/chat.ts +0 -130
  58. package/src/modules/v4/color.ts +0 -75
  59. package/src/modules/v4/convert.ts +0 -127
  60. package/src/modules/v4/cron.ts +0 -221
  61. package/src/modules/v4/dice.ts +0 -46
  62. package/src/modules/v4/domain.ts +0 -86
  63. package/src/modules/v4/encode.ts +0 -241
  64. package/src/modules/v4/geo.ts +0 -64
  65. package/src/modules/v4/hash.ts +0 -32
  66. package/src/modules/v4/hyperplanning.ts +0 -93
  67. package/src/modules/v4/ip.ts +0 -134
  68. package/src/modules/v4/levenshtein.ts +0 -46
  69. package/src/modules/v4/palette.ts +0 -71
  70. package/src/modules/v4/password.ts +0 -379
  71. package/src/modules/v4/personal.ts +0 -140
  72. package/src/modules/v4/placeholder.ts +0 -197
  73. package/src/modules/v4/qrcode.ts +0 -121
  74. package/src/modules/v4/regex.ts +0 -67
  75. package/src/modules/v4/statistics.ts +0 -62
  76. package/src/modules/v4/text.ts +0 -330
  77. package/src/modules/v4/tic_tac_toe.ts +0 -264
  78. package/src/modules/v4/time.ts +0 -149
  79. package/src/modules/v4/token.ts +0 -53
  80. package/src/modules/v4/username.ts +0 -94
  81. package/src/modules/v4/validate.ts +0 -76
  82. package/src/modules/v4.ts +0 -29
  83. package/src/routes/delete.ts +0 -72
  84. package/src/routes/get.ts +0 -856
  85. package/src/routes/index.ts +0 -59
  86. package/src/routes/patch.ts +0 -45
  87. package/src/routes/post.ts +0 -209
  88. package/src/storage/index.ts +0 -16
  89. package/src/types/express.d.ts +0 -17
  90. package/src/types/storage.ts +0 -48
  91. package/src/utils/colors.ts +0 -91
  92. package/src/utils/helpers.ts +0 -90
  93. package/src/utils/response.ts +0 -28
  94. package/tests/integration/api.test.ts +0 -772
  95. package/tests/tsconfig.json +0 -3
  96. package/tests/unit/address.test.ts +0 -84
  97. package/tests/unit/agent.test.ts +0 -113
  98. package/tests/unit/algorithms.test.ts +0 -121
  99. package/tests/unit/captcha.test.ts +0 -62
  100. package/tests/unit/chat.test.ts +0 -54
  101. package/tests/unit/color.test.ts +0 -54
  102. package/tests/unit/convert.test.ts +0 -68
  103. package/tests/unit/cron.test.ts +0 -110
  104. package/tests/unit/dice.test.ts +0 -58
  105. package/tests/unit/domain.test.ts +0 -48
  106. package/tests/unit/encode.test.ts +0 -109
  107. package/tests/unit/geo.test.ts +0 -46
  108. package/tests/unit/hash.test.ts +0 -45
  109. package/tests/unit/hyperplanning.test.ts +0 -97
  110. package/tests/unit/ip.test.ts +0 -140
  111. package/tests/unit/levenshtein.test.ts +0 -35
  112. package/tests/unit/palette.test.ts +0 -54
  113. package/tests/unit/password.test.ts +0 -86
  114. package/tests/unit/personal.test.ts +0 -66
  115. package/tests/unit/placeholder.test.ts +0 -58
  116. package/tests/unit/qrcode.test.ts +0 -83
  117. package/tests/unit/regex.test.ts +0 -95
  118. package/tests/unit/statistics.test.ts +0 -58
  119. package/tests/unit/text.test.ts +0 -108
  120. package/tests/unit/tic_tac_toe.test.ts +0 -56
  121. package/tests/unit/time.test.ts +0 -115
  122. package/tests/unit/token.test.ts +0 -62
  123. package/tests/unit/username.test.ts +0 -35
  124. package/tests/unit/validate.test.ts +0 -72
  125. package/tsconfig.json +0 -17
  126. package/tsconfig.test.json +0 -9
@@ -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
- }
@@ -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';
@@ -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;