@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.
Files changed (213) hide show
  1. package/.prettierrc +7 -0
  2. package/README.md +32 -33
  3. package/dist/app.js +36 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/config/env.js +73 -0
  6. package/dist/config/env.js.map +1 -0
  7. package/dist/config/versions.js +72 -0
  8. package/dist/config/versions.js.map +1 -0
  9. package/dist/constants.js +42 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/middleware/cors.js +15 -0
  12. package/dist/middleware/cors.js.map +1 -0
  13. package/dist/middleware/error.js +6 -0
  14. package/dist/middleware/error.js.map +1 -0
  15. package/dist/middleware/json.js +8 -0
  16. package/dist/middleware/json.js.map +1 -0
  17. package/dist/middleware/logger.js +26 -0
  18. package/dist/middleware/logger.js.map +1 -0
  19. package/dist/middleware/ratelimit.js +58 -0
  20. package/dist/middleware/ratelimit.js.map +1 -0
  21. package/dist/middleware/version.js +30 -0
  22. package/dist/middleware/version.js.map +1 -0
  23. package/dist/modules/v3/algorithms.js +221 -0
  24. package/dist/modules/v3/algorithms.js.map +1 -0
  25. package/{modules → dist/modules}/v3/captcha.js +4 -13
  26. package/dist/modules/v3/captcha.js.map +1 -0
  27. package/dist/modules/v3/chat.js +103 -0
  28. package/dist/modules/v3/chat.js.map +1 -0
  29. package/{modules → dist/modules}/v3/color.js +12 -13
  30. package/dist/modules/v3/color.js.map +1 -0
  31. package/dist/modules/v3/convert.js +41 -0
  32. package/dist/modules/v3/convert.js.map +1 -0
  33. package/dist/modules/v3/domain.js +83 -0
  34. package/dist/modules/v3/domain.js.map +1 -0
  35. package/dist/modules/v3/hash.js +16 -0
  36. package/dist/modules/v3/hash.js.map +1 -0
  37. package/dist/modules/v3/hyperplanning.js +50 -0
  38. package/dist/modules/v3/hyperplanning.js.map +1 -0
  39. package/dist/modules/v3/levenshtein.js +38 -0
  40. package/dist/modules/v3/levenshtein.js.map +1 -0
  41. package/dist/modules/v3/personal.js +129 -0
  42. package/dist/modules/v3/personal.js.map +1 -0
  43. package/dist/modules/v3/qrcode.js +21 -0
  44. package/dist/modules/v3/qrcode.js.map +1 -0
  45. package/dist/modules/v3/tic_tac_toe.js +221 -0
  46. package/dist/modules/v3/tic_tac_toe.js.map +1 -0
  47. package/dist/modules/v3/time.js +88 -0
  48. package/dist/modules/v3/time.js.map +1 -0
  49. package/{modules → dist/modules}/v3/token.js +10 -11
  50. package/dist/modules/v3/token.js.map +1 -0
  51. package/dist/modules/v3/username.js +92 -0
  52. package/dist/modules/v3/username.js.map +1 -0
  53. package/dist/modules/v3/utils.js +70 -0
  54. package/dist/modules/v3/utils.js.map +1 -0
  55. package/dist/modules/v3.js +16 -0
  56. package/dist/modules/v3.js.map +1 -0
  57. package/dist/modules/v4/algorithms.js +200 -0
  58. package/dist/modules/v4/algorithms.js.map +1 -0
  59. package/dist/modules/v4/captcha.js +35 -0
  60. package/dist/modules/v4/captcha.js.map +1 -0
  61. package/dist/modules/v4/chat.js +92 -0
  62. package/dist/modules/v4/chat.js.map +1 -0
  63. package/dist/modules/v4/color.js +43 -0
  64. package/dist/modules/v4/color.js.map +1 -0
  65. package/dist/modules/v4/convert.js +33 -0
  66. package/dist/modules/v4/convert.js.map +1 -0
  67. package/dist/modules/v4/dice.js +30 -0
  68. package/dist/modules/v4/dice.js.map +1 -0
  69. package/dist/modules/v4/domain.js +78 -0
  70. package/dist/modules/v4/domain.js.map +1 -0
  71. package/dist/modules/v4/encode.js +165 -0
  72. package/dist/modules/v4/encode.js.map +1 -0
  73. package/dist/modules/v4/geo.js +41 -0
  74. package/dist/modules/v4/geo.js.map +1 -0
  75. package/dist/modules/v4/hash.js +9 -0
  76. package/dist/modules/v4/hash.js.map +1 -0
  77. package/dist/modules/v4/hyperplanning.js +42 -0
  78. package/dist/modules/v4/hyperplanning.js.map +1 -0
  79. package/dist/modules/v4/levenshtein.js +29 -0
  80. package/dist/modules/v4/levenshtein.js.map +1 -0
  81. package/dist/modules/v4/palette.js +89 -0
  82. package/dist/modules/v4/palette.js.map +1 -0
  83. package/dist/modules/v4/personal.js +125 -0
  84. package/dist/modules/v4/personal.js.map +1 -0
  85. package/dist/modules/v4/placeholder.js +96 -0
  86. package/dist/modules/v4/placeholder.js.map +1 -0
  87. package/dist/modules/v4/qrcode.js +12 -0
  88. package/dist/modules/v4/qrcode.js.map +1 -0
  89. package/dist/modules/v4/statistics.js +41 -0
  90. package/dist/modules/v4/statistics.js.map +1 -0
  91. package/dist/modules/v4/text.js +293 -0
  92. package/dist/modules/v4/text.js.map +1 -0
  93. package/dist/modules/v4/tic_tac_toe.js +206 -0
  94. package/dist/modules/v4/tic_tac_toe.js.map +1 -0
  95. package/dist/modules/v4/time.js +73 -0
  96. package/dist/modules/v4/time.js.map +1 -0
  97. package/dist/modules/v4/token.js +36 -0
  98. package/dist/modules/v4/token.js.map +1 -0
  99. package/dist/modules/v4/username.js +87 -0
  100. package/dist/modules/v4/username.js.map +1 -0
  101. package/dist/modules/v4/utils.js +26 -0
  102. package/dist/modules/v4/utils.js.map +1 -0
  103. package/dist/modules/v4/validate.js +54 -0
  104. package/dist/modules/v4/validate.js.map +1 -0
  105. package/dist/modules/v4.js +18 -0
  106. package/dist/modules/v4.js.map +1 -0
  107. package/dist/routes/delete.js +65 -0
  108. package/dist/routes/delete.js.map +1 -0
  109. package/dist/routes/get.js +441 -0
  110. package/dist/routes/get.js.map +1 -0
  111. package/dist/routes/index.js +50 -0
  112. package/dist/routes/index.js.map +1 -0
  113. package/dist/routes/patch.js +41 -0
  114. package/dist/routes/patch.js.map +1 -0
  115. package/dist/routes/post.js +185 -0
  116. package/dist/routes/post.js.map +1 -0
  117. package/dist/storage/index.js +13 -0
  118. package/dist/storage/index.js.map +1 -0
  119. package/dist/types/storage.js +2 -0
  120. package/dist/types/storage.js.map +1 -0
  121. package/dist/utils/response.js +10 -0
  122. package/dist/utils/response.js.map +1 -0
  123. package/dist/utils/version.js +3 -0
  124. package/dist/utils/version.js.map +1 -0
  125. package/docs/changelog.md +333 -0
  126. package/eslint.config.js +20 -0
  127. package/package.json +31 -15
  128. package/src/app.ts +48 -0
  129. package/src/config/env.ts +81 -0
  130. package/src/config/versions.ts +92 -0
  131. package/src/constants.ts +47 -0
  132. package/src/middleware/cors.ts +17 -0
  133. package/src/middleware/error.ts +7 -0
  134. package/src/middleware/json.ts +9 -0
  135. package/src/middleware/logger.ts +31 -0
  136. package/src/middleware/ratelimit.ts +66 -0
  137. package/src/middleware/version.ts +39 -0
  138. package/{modules → src/modules}/v3/algorithms.js +1 -1
  139. package/src/modules/v3/captcha.js +60 -0
  140. package/{modules → src/modules}/v3/chat.js +6 -4
  141. package/src/modules/v3/color.js +60 -0
  142. package/{modules → src/modules}/v3/convert.js +5 -5
  143. package/{modules → src/modules}/v3/domain.js +51 -4
  144. package/{modules → src/modules}/v3/hash.js +1 -1
  145. package/{modules → src/modules}/v3/hyperplanning.js +11 -10
  146. package/{modules → src/modules}/v3/levenshtein.js +3 -3
  147. package/{modules → src/modules}/v3/personal.js +20 -8
  148. package/{modules → src/modules}/v3/qrcode.js +1 -1
  149. package/{modules → src/modules}/v3/tic_tac_toe.js +24 -18
  150. package/{modules → src/modules}/v3/time.js +22 -11
  151. package/src/modules/v3/token.js +54 -0
  152. package/src/modules/v3/username.js +94 -0
  153. package/{modules → src/modules}/v3/utils.js +2 -2
  154. package/{modules → src/modules}/v3.js +1 -1
  155. package/src/modules/v4/algorithms.ts +197 -0
  156. package/src/modules/v4/captcha.ts +49 -0
  157. package/src/modules/v4/chat.ts +122 -0
  158. package/src/modules/v4/color.ts +64 -0
  159. package/src/modules/v4/convert.ts +38 -0
  160. package/src/modules/v4/dice.ts +39 -0
  161. package/src/modules/v4/domain.ts +81 -0
  162. package/src/modules/v4/encode.ts +170 -0
  163. package/src/modules/v4/geo.ts +53 -0
  164. package/src/modules/v4/hash.ts +9 -0
  165. package/src/modules/v4/hyperplanning.ts +58 -0
  166. package/src/modules/v4/levenshtein.ts +38 -0
  167. package/src/modules/v4/palette.ts +103 -0
  168. package/src/modules/v4/personal.ts +147 -0
  169. package/src/modules/v4/placeholder.ts +122 -0
  170. package/src/modules/v4/qrcode.ts +11 -0
  171. package/src/modules/v4/statistics.ts +55 -0
  172. package/src/modules/v4/text.ts +300 -0
  173. package/src/modules/v4/tic_tac_toe.ts +255 -0
  174. package/src/modules/v4/time.ts +92 -0
  175. package/src/modules/v4/token.ts +43 -0
  176. package/src/modules/v4/username.ts +89 -0
  177. package/src/modules/v4/utils.ts +38 -0
  178. package/src/modules/v4/validate.ts +55 -0
  179. package/src/modules/v4.ts +17 -0
  180. package/src/routes/delete.ts +72 -0
  181. package/src/routes/get.ts +508 -0
  182. package/src/routes/index.ts +58 -0
  183. package/src/routes/patch.ts +45 -0
  184. package/src/routes/post.ts +200 -0
  185. package/src/storage/index.ts +16 -0
  186. package/src/types/express.d.ts +17 -0
  187. package/src/types/storage.ts +48 -0
  188. package/src/utils/response.ts +11 -0
  189. package/src/utils/version.ts +5 -0
  190. package/tests/integration/api.test.ts +395 -0
  191. package/tests/tsconfig.json +3 -0
  192. package/tests/unit/algorithms.test.ts +120 -0
  193. package/tests/unit/color.test.ts +33 -0
  194. package/tests/unit/convert.test.ts +42 -0
  195. package/tests/unit/dice.test.ts +57 -0
  196. package/tests/unit/domain.test.ts +47 -0
  197. package/tests/unit/encode.test.ts +108 -0
  198. package/tests/unit/geo.test.ts +45 -0
  199. package/tests/unit/hash.test.ts +37 -0
  200. package/tests/unit/hyperplanning.test.ts +77 -0
  201. package/tests/unit/levenshtein.test.ts +34 -0
  202. package/tests/unit/palette.test.ts +53 -0
  203. package/tests/unit/personal.test.ts +65 -0
  204. package/tests/unit/statistics.test.ts +57 -0
  205. package/tests/unit/text.test.ts +107 -0
  206. package/tests/unit/time.test.ts +67 -0
  207. package/tests/unit/token.test.ts +61 -0
  208. package/tests/unit/username.test.ts +34 -0
  209. package/tests/unit/validate.test.ts +71 -0
  210. package/tsconfig.json +17 -0
  211. package/tsconfig.test.json +9 -0
  212. package/app.js +0 -865
  213. package/modules/v3/username.js +0 -32
@@ -0,0 +1,197 @@
1
+ import { MAX_FACTORIAL, MAX_GCD_VALUE, MAX_PRIME_LIST, MAX_STRING_LENGTH, ROMAN_VALUES } from '../../constants.js';
2
+
3
+ export function anagram(value: string, value2: string): boolean {
4
+ if (!value) throw new Error('First value is required');
5
+ if (!value2) throw new Error('Second value is required');
6
+
7
+ if (typeof value !== 'string') throw new Error('First value must be a string');
8
+ if (typeof value2 !== 'string') throw new Error('Second value must be a string');
9
+
10
+ if (value.length < 2) throw new Error('First value must be at least two characters long');
11
+ if (value.length > MAX_STRING_LENGTH) throw new Error('First value must be less than 1000 characters long');
12
+
13
+ if (value2.length < 2) throw new Error('Second value must be at least two characters long');
14
+ if (value2.length > MAX_STRING_LENGTH) throw new Error('Second value must be less than 1000 characters long');
15
+
16
+ return value.split('').sort().join('') === value2.split('').sort().join('');
17
+ }
18
+
19
+ export function bubblesort(value: string): number[] {
20
+ if (!value) throw new Error('A value is required');
21
+
22
+ if (typeof value !== 'string') throw new Error('Value must be a string');
23
+
24
+ const arr = value.split(',').map(Number);
25
+
26
+ if (arr.some(isNaN)) throw new Error('Array must contain only numbers');
27
+ if (arr.length < 2) throw new Error('Array must contain at least two numbers');
28
+ if (arr.length > MAX_STRING_LENGTH) throw new Error('Array must contain less than 1000 numbers');
29
+
30
+ for (let i = 0; i < arr.length - 1; i++) {
31
+ for (let j = 0; j < arr.length - i - 1; j++) {
32
+ if (arr[j]! > arr[j + 1]!) [arr[j], arr[j + 1]] = [arr[j + 1]!, arr[j]!];
33
+ }
34
+ }
35
+
36
+ return arr;
37
+ }
38
+
39
+ export function factorial(value: string | number): number {
40
+ const num = Number(value);
41
+ if (isNaN(num)) throw new Error('Value must be a number');
42
+ if (num < 0) throw new Error('Number must be positive');
43
+ if (num > MAX_FACTORIAL) throw new Error('Number must be between 0 and 170');
44
+
45
+ return num <= 1 ? 1 : num * factorial(num - 1);
46
+ }
47
+
48
+ export function fibonacci(value: string | number): number[] {
49
+ const num = Number(value);
50
+ if (isNaN(num)) throw new Error('Value must be a number');
51
+ if (num < 0) throw new Error('Number must be positive');
52
+ if (num > 1000) throw new Error('Number must be between 0 and 1000');
53
+
54
+ const fib = [0, 1];
55
+
56
+ for (let i = 2; i < num; i++) {
57
+ fib.push(fib[i - 1]! + fib[i - 2]!);
58
+ }
59
+
60
+ return fib.slice(0, num);
61
+ }
62
+
63
+ export function gcd(value: string | number, value2: string | number): number {
64
+ let a = Number(value);
65
+ let b = Number(value2);
66
+ if (isNaN(a)) throw new Error('First value must be a number');
67
+ if (isNaN(b)) throw new Error('Second value must be a number');
68
+
69
+ if (a <= 0) throw new Error('First number must be strictly positive');
70
+ if (b <= 0) throw new Error('Second number must be strictly positive');
71
+
72
+ if (a > MAX_GCD_VALUE) throw new Error('First number must be between 0 and 100000');
73
+ if (b > MAX_GCD_VALUE) throw new Error('Second number must be between 0 and 100000');
74
+
75
+ a = Math.abs(a);
76
+ b = Math.abs(b);
77
+
78
+ while (b) [a, b] = [b, a % b];
79
+
80
+ return a;
81
+ }
82
+
83
+ export function isprime(value: string | number): boolean {
84
+ const num = Number(value);
85
+ if (isNaN(num)) throw new Error('Value must be a number');
86
+ if (num < 1) throw new Error('Number must be positive');
87
+ if (num > MAX_GCD_VALUE) throw new Error('Number must be between 1 and 100000');
88
+
89
+ for (let i = 2; i <= Math.sqrt(num); i++) {
90
+ if (num % i === 0) return false;
91
+ }
92
+
93
+ return true;
94
+ }
95
+
96
+ export function palindrome(value: string): boolean {
97
+ if (!value) throw new Error('A value is required');
98
+
99
+ if (typeof value !== 'string') throw new Error('Value must be a string');
100
+
101
+ if (value.length < 2) throw new Error('Value must be at least two characters long');
102
+ if (value.length > MAX_STRING_LENGTH) throw new Error('Value must be less than 1000 characters long');
103
+
104
+ return value === value.split('').reverse().join('');
105
+ }
106
+
107
+ export function primefactors(value: string | number): number[] {
108
+ let num = Number(value);
109
+ if (isNaN(num)) throw new Error('Value must be a number');
110
+ if (num < 2) throw new Error('Number must be positive and greater than 1');
111
+ if (num > MAX_GCD_VALUE) throw new Error('Number must be between 2 and 100000');
112
+
113
+ const factors: number[] = [];
114
+
115
+ for (let i = 2; i <= num; i++) {
116
+ while (num % i === 0) {
117
+ factors.push(i);
118
+ num /= i;
119
+ }
120
+ }
121
+
122
+ return factors;
123
+ }
124
+
125
+ export function primelist(value: string | number): number[] {
126
+ const num = Number(value);
127
+ if (isNaN(num)) throw new Error('Value must be a number');
128
+ if (num < 2) throw new Error('Number must be positive and greater than 1');
129
+ if (num > MAX_PRIME_LIST) throw new Error('Number must be between 2 and 10000');
130
+
131
+ const primes: number[] = [];
132
+
133
+ for (let i = 2; i <= num; i++) {
134
+ let isPrime = true;
135
+
136
+ for (let j = 2; j <= Math.sqrt(i); j++) {
137
+ if (i % j === 0) {
138
+ isPrime = false;
139
+ break;
140
+ }
141
+ }
142
+
143
+ if (isPrime) primes.push(i);
144
+ }
145
+
146
+ return primes;
147
+ }
148
+
149
+ export function reverse(value: string): string {
150
+ if (!value) throw new Error('A value is required');
151
+
152
+ if (typeof value !== 'string') throw new Error('Value must be a string');
153
+
154
+ return value.split('').reverse().join('');
155
+ }
156
+
157
+ export function roman(value: string): number | string {
158
+ if (!value) throw new Error('A value is required');
159
+
160
+ const num = Number(value);
161
+ if (!isNaN(num)) {
162
+ if (!Number.isInteger(num)) throw new Error('Value must be an integer');
163
+ if (num < 1 || num > 3999) throw new Error('Number must be between 1 and 3999');
164
+
165
+ let result = '';
166
+ let n = num;
167
+ for (const [val, sym] of ROMAN_VALUES) {
168
+ while (n >= val) {
169
+ result += sym;
170
+ n -= val;
171
+ }
172
+ }
173
+ return result;
174
+ }
175
+
176
+ if (typeof value !== 'string') throw new Error('Value must be a number or a Roman numeral');
177
+ const upper = value.toUpperCase();
178
+ if (!/^[MDCLXVI]+$/.test(upper)) throw new Error('Invalid Roman numeral');
179
+
180
+ let result = 0;
181
+ let i = 0;
182
+ while (i < upper.length) {
183
+ const two = upper.slice(i, i + 2);
184
+ const match = ROMAN_VALUES.find(([, sym]) => sym === two);
185
+ if (match) {
186
+ result += match[0];
187
+ i += 2;
188
+ } else {
189
+ const one = ROMAN_VALUES.find(([, sym]) => sym === upper[i]);
190
+ if (!one) throw new Error('Invalid Roman numeral');
191
+ result += one[0];
192
+ i += 1;
193
+ }
194
+ }
195
+
196
+ return result;
197
+ }
@@ -0,0 +1,49 @@
1
+ import { createCanvas } from 'canvas';
2
+
3
+ export default function captcha(text: string): Buffer {
4
+ if (!text) throw new Error('Text is required to generate a captcha.');
5
+
6
+ const size = 60,
7
+ font = '60px Comic Sans Ms',
8
+ width = text.length * size,
9
+ height = 120;
10
+ const canvas = createCanvas(width, height),
11
+ ctx = canvas.getContext('2d');
12
+
13
+ ctx.fillStyle = 'white';
14
+ ctx.fillRect(0, 0, width, height);
15
+
16
+ for (let i = 0; i < 20; i++) {
17
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
18
+ ctx.beginPath();
19
+ ctx.moveTo(Math.random() * width, Math.random() * height);
20
+ ctx.lineTo(Math.random() * width, Math.random() * height);
21
+ ctx.lineWidth = Math.random() * 2;
22
+ ctx.stroke();
23
+ }
24
+
25
+ let x = (canvas.width + 20 - width) / 2;
26
+
27
+ for (let i = 0; i < text.length; i++) {
28
+ const offsetX = Math.cos(i * 0.3) * 10,
29
+ y = height / 2.5 + Math.floor(Math.random() * (height / 2));
30
+
31
+ ctx.font = font;
32
+ ctx.fillStyle = `rgb(${Math.floor(Math.random() * 192)}, ${Math.floor(Math.random() * 192)}, ${Math.floor(Math.random() * 192)})`;
33
+
34
+ ctx.save();
35
+ ctx.translate(x + size / 2, y);
36
+ ctx.rotate((Math.random() - 0.5) * 0.5);
37
+ ctx.fillText(text[i]!, -size / 2 + offsetX, 0);
38
+ ctx.restore();
39
+
40
+ x += size;
41
+ }
42
+
43
+ for (let i = 0; i < 200; i++) {
44
+ ctx.fillStyle = 'black';
45
+ ctx.fillRect(Math.floor(Math.random() * width), Math.floor(Math.random() * height), 1.2, 1.2);
46
+ }
47
+
48
+ return canvas.toBuffer('image/png');
49
+ }
@@ -0,0 +1,122 @@
1
+ import { checkRateLimit } from './utils.js';
2
+ import { SESSION_TTL } from '../../constants.js';
3
+ import type { ChatStorage, ChatMessage } from '../../types/storage.js';
4
+
5
+ interface ChatParams {
6
+ username: string;
7
+ message?: string;
8
+ timestamp?: string;
9
+ session?: string;
10
+ token?: string;
11
+ storage: ChatStorage;
12
+ }
13
+
14
+ export default function chat(action: string, params: ChatParams): ChatMessage[] | ChatMessage | { message: string } {
15
+ const storage = params.storage;
16
+
17
+ storage.messages ??= [];
18
+ storage.privateChats ??= {};
19
+ storage.sessions ??= {};
20
+ storage.rateLimits ??= {};
21
+
22
+ const { messages, privateChats, sessions, rateLimits } = storage;
23
+
24
+ if (!params.username) throw new Error('Please provide a username');
25
+
26
+ const u = params.username.toLowerCase();
27
+ const now = Date.now();
28
+
29
+ checkRateLimit(rateLimits, u, now);
30
+
31
+ if (action === 'message') {
32
+ return sendMessage(params, messages, privateChats, sessions, u, now);
33
+ } else if (action === 'private') {
34
+ return getPrivateChat(params, privateChats);
35
+ } else if (action === 'fetch') {
36
+ return fetchMessages(messages);
37
+ } else if (action === 'clear') {
38
+ return clearPrivateChat(params, privateChats, sessions, u);
39
+ } else {
40
+ throw new Error('Invalid action. Use "message", "private", "fetch", or "clear"');
41
+ }
42
+ }
43
+
44
+ function sendMessage(
45
+ params: ChatParams,
46
+ messages: ChatMessage[],
47
+ privateChats: Record<string, ChatMessage[]>,
48
+ sessions: Record<string, { user: string; last: number }>,
49
+ u: string,
50
+ now: number,
51
+ ): { message: string } {
52
+ const { message, session, token } = params;
53
+
54
+ if (!message) throw new Error('Please provide a message');
55
+ if (!session) throw new Error('Please provide a valid session ID');
56
+
57
+ if (sessions[u] && sessions[u].user !== session) {
58
+ throw new Error('Session ID mismatch');
59
+ }
60
+
61
+ const msg: ChatMessage = {
62
+ username: params.username,
63
+ message,
64
+ timestamp: params.timestamp || new Date().toISOString(),
65
+ };
66
+
67
+ if (token) {
68
+ privateChats[token] = privateChats[token] || [];
69
+ privateChats[token]!.push(msg);
70
+ setTimeout(() => {
71
+ delete privateChats[token];
72
+ }, SESSION_TTL);
73
+ } else {
74
+ messages.push(msg);
75
+ setTimeout(() => messages.splice(messages.indexOf(msg), 1), SESSION_TTL);
76
+ }
77
+
78
+ sessions[u] = sessions[u] || { user: session, last: now };
79
+ sessions[u]!.last = now;
80
+
81
+ setTimeout(() => {
82
+ if (sessions[u] && now - sessions[u].last >= SESSION_TTL) delete sessions[u];
83
+ }, SESSION_TTL);
84
+
85
+ return { message: 'Message sent successfully' };
86
+ }
87
+
88
+ function getPrivateChat(params: ChatParams, privateChats: Record<string, ChatMessage[]>): ChatMessage[] {
89
+ const { token } = params;
90
+
91
+ if (!token) throw new Error('Please provide a valid token');
92
+
93
+ if (privateChats[token]) return privateChats[token];
94
+
95
+ throw new Error('Invalid or expired token.');
96
+ }
97
+
98
+ function fetchMessages(messages: ChatMessage[]): ChatMessage[] {
99
+ if (messages.length > 0) return messages;
100
+ throw new Error('No messages stored.');
101
+ }
102
+
103
+ function clearPrivateChat(
104
+ params: ChatParams,
105
+ privateChats: Record<string, ChatMessage[]>,
106
+ sessions: Record<string, { user: string; last: number }>,
107
+ u: string,
108
+ ): { message: string } {
109
+ const { token, session } = params;
110
+
111
+ if (!token) throw new Error('Please provide a valid token');
112
+ if (!session) throw new Error('Please provide a valid session ID');
113
+ if (sessions[u] && sessions[u].user !== session) {
114
+ throw new Error('Session ID mismatch');
115
+ }
116
+ if (!privateChats[token]) throw new Error('Invalid or expired token.');
117
+
118
+ delete privateChats[token];
119
+ delete sessions[u];
120
+
121
+ return { message: 'Private chat cleared successfully' };
122
+ }
@@ -0,0 +1,64 @@
1
+ export default function color(): Record<string, string> {
2
+ const r = Math.floor(Math.random() * 256),
3
+ g = Math.floor(Math.random() * 256),
4
+ b = Math.floor(Math.random() * 256);
5
+
6
+ const hsl = ((): [number, number, number] => {
7
+ const r1 = r / 255,
8
+ g1 = g / 255,
9
+ b1 = b / 255,
10
+ max = Math.max(r1, g1, b1),
11
+ min = Math.min(r1, g1, b1),
12
+ l = (max + min) / 2;
13
+ if (max === min) return [0, 0, l * 100];
14
+ const d = max - min,
15
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
16
+ const h =
17
+ {
18
+ [r1]: (g1 - b1) / d + (g1 < b1 ? 6 : 0),
19
+ [g1]: (b1 - r1) / d + 2,
20
+ [b1]: (r1 - g1) / d + 4,
21
+ }[max] ?? 0;
22
+ return [(h * 60) % 360, s * 100, l * 100];
23
+ })();
24
+
25
+ const hsv = ((): [number, number, number] => {
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
+ const h =
31
+ max === min
32
+ ? 0
33
+ : ({
34
+ [r]: (g - b) / (max - min),
35
+ [g]: 2 + (b - r) / (max - min),
36
+ [b]: 4 + (r - g) / (max - min),
37
+ }[max] ?? 0);
38
+ return [(h * 60) % 360, s * 100, v * 100];
39
+ })();
40
+
41
+ const hwb = ((): [number, number, number] => {
42
+ const [h] = hsv,
43
+ whiteness = Math.min(r, g, b) / 255,
44
+ blackness = 1 - Math.max(r, g, b) / 255;
45
+ return [h, whiteness * 100, blackness * 100];
46
+ })();
47
+
48
+ const cmyk = ((): [number, number, number, number] => {
49
+ const k = 1 - Math.max(r, g, b) / 255,
50
+ c = (1 - r / 255 - k) / (1 - k) || 0,
51
+ m = (1 - g / 255 - k) / (1 - k) || 0,
52
+ y = (1 - b / 255 - k) / (1 - k) || 0;
53
+ return [c * 100, m * 100, y * 100, k * 100];
54
+ })();
55
+
56
+ return {
57
+ hex: `#${[r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('')}`,
58
+ rgb: `rgb(${r}, ${g}, ${b})`,
59
+ hsl: `hsl(${hsl[0].toFixed(1)}, ${hsl[1].toFixed(1)}%, ${hsl[2].toFixed(1)}%)`,
60
+ hsv: `hsv(${hsv[0].toFixed(1)}, ${hsv[1].toFixed(1)}%, ${hsv[2].toFixed(1)}%)`,
61
+ hwb: `hwb(${hwb[0].toFixed(1)}, ${hwb[1].toFixed(1)}%, ${hwb[2].toFixed(1)}%)`,
62
+ cmyk: `cmyk(${cmyk.map((x) => x.toFixed(1)).join('%, ')}%)`,
63
+ };
64
+ }
@@ -0,0 +1,38 @@
1
+ import { MIN_TEMPERATURE, MAX_TEMPERATURE } from '../../constants.js';
2
+
3
+ type ConversionFn = (val: number) => number;
4
+
5
+ const conversions: Record<string, Record<string, ConversionFn>> = {
6
+ celsius: {
7
+ fahrenheit: (val) => (val * 9) / 5 + 32,
8
+ kelvin: (val) => val + 273.15,
9
+ },
10
+ fahrenheit: {
11
+ celsius: (val) => ((val - 32) * 5) / 9,
12
+ kelvin: (val) => ((val - 32) * 5) / 9 + 273.15,
13
+ },
14
+ kelvin: {
15
+ celsius: (val) => val - 273.15,
16
+ fahrenheit: (val) => ((val - 273.15) * 9) / 5 + 32,
17
+ },
18
+ };
19
+
20
+ export default function convert(
21
+ value: string | number,
22
+ from: string,
23
+ to: string,
24
+ ): { from: string; to: string; value: number; result: number } {
25
+ const convertFn = conversions[from.toLowerCase()]?.[to.toLowerCase()];
26
+
27
+ if (!convertFn) throw new Error('Invalid conversion unit');
28
+ if (isNaN(Number(value))) throw new Error('Value must be a number');
29
+ if (Number(value) < MIN_TEMPERATURE) throw new Error('Value must be greater than absolute zero');
30
+ if (Number(value) > MAX_TEMPERATURE) throw new Error('Value must be less than 1,000,000');
31
+
32
+ return {
33
+ from,
34
+ to,
35
+ value: parseFloat(String(value)),
36
+ result: convertFn(parseFloat(String(value))),
37
+ };
38
+ }
@@ -0,0 +1,39 @@
1
+ export interface DiceResult {
2
+ roll: string;
3
+ count: number;
4
+ sides: number;
5
+ modifier: number;
6
+ results: number[];
7
+ total: number;
8
+ }
9
+
10
+ export default function dice(roll: string): DiceResult {
11
+ if (!roll) throw new Error('A roll notation is required (e.g. 2d6+3)');
12
+ if (typeof roll !== 'string') throw new Error('Roll must be a string');
13
+
14
+ const match = /^(\d*)d(\d+)([+-]\d+)?$/i.exec(roll.trim().replace(/\s+/g, '+'));
15
+ if (!match) throw new Error('Invalid notation. Use NdX or NdX+M (e.g. 2d6+3)');
16
+
17
+ const count = match[1] ? parseInt(match[1], 10) : 1;
18
+ const sides = parseInt(match[2]!, 10);
19
+ const modifier = match[3] ? parseInt(match[3], 10) : 0;
20
+
21
+ if (count < 1 || count > 100) throw new Error('Number of dice must be between 1 and 100');
22
+ if (sides < 2 || sides > 1000) throw new Error('Number of sides must be between 2 and 1000');
23
+
24
+ const results: number[] = [];
25
+ for (let i = 0; i < count; i++) {
26
+ results.push(1 + Math.floor(Math.random() * sides));
27
+ }
28
+
29
+ const total = results.reduce((a, b) => a + b, 0) + modifier;
30
+
31
+ return {
32
+ roll: `${count}d${sides}${modifier ? (modifier > 0 ? `+${modifier}` : modifier) : ''}`,
33
+ count,
34
+ sides,
35
+ modifier,
36
+ results,
37
+ total,
38
+ };
39
+ }
@@ -0,0 +1,81 @@
1
+ import { random, genIP } from './utils.js';
2
+
3
+ export default function domain(): Record<string, unknown> {
4
+ const subdomains = [
5
+ 'fr.',
6
+ 'en.',
7
+ 'docs.',
8
+ 'api.',
9
+ 'projects.',
10
+ 'app.',
11
+ 'web.',
12
+ 'info.',
13
+ 'dev.',
14
+ 'shop.',
15
+ 'blog.',
16
+ 'support.',
17
+ 'mail.',
18
+ 'forum.',
19
+ ];
20
+ const domains = [
21
+ 'example',
22
+ 'site',
23
+ 'test',
24
+ 'demo',
25
+ 'page',
26
+ 'store',
27
+ 'portfolio',
28
+ 'platform',
29
+ 'hub',
30
+ 'network',
31
+ 'service',
32
+ 'cloud',
33
+ 'solutions',
34
+ 'company',
35
+ ];
36
+ const tlds = [
37
+ '.com',
38
+ '.fr',
39
+ '.eu',
40
+ '.dev',
41
+ '.net',
42
+ '.org',
43
+ '.io',
44
+ '.tech',
45
+ '.biz',
46
+ '.info',
47
+ '.co',
48
+ '.app',
49
+ '.store',
50
+ '.online',
51
+ '.shop',
52
+ '.tv',
53
+ ];
54
+
55
+ const domainName = `${random(domains)}${random(tlds)}`;
56
+ const fulldomain = `${random(subdomains)}${domainName}`;
57
+
58
+ const ips = Array.from({ length: Math.floor(Math.random() * 3) + 1 }, genIP);
59
+ const dns = Array.from({ length: Math.floor(Math.random() * 5) + 1 }, genIP);
60
+
61
+ return {
62
+ domain: domainName,
63
+ full_domain: fulldomain,
64
+ ip_address: ips,
65
+ ssl_certified: Math.random() > 0.5,
66
+ hosting_provider: random(['AWS', 'Bluehost', 'DigitalOcean', 'GitHub', 'HostGator', 'Render', 'SiteGround']),
67
+ dns_servers: dns,
68
+ dns_provider: random(['AWS Route 53', 'Cloudflare', 'GoDaddy', 'Google DNS', 'Namecheap']),
69
+ traffic: `${Math.floor(Math.random() * 10000)} visits/day`,
70
+ seo_score: Math.floor(Math.random() * 100),
71
+ page_rank: Math.floor(Math.random() * 10),
72
+ country: random(['Australia', 'Canada', 'France', 'Germany', 'India', 'Japan', 'UK', 'USA']),
73
+ website_type: random(['Blog', 'Community', 'Corporate', 'Educational', 'E-commerce', 'Personal', 'Portfolio']),
74
+ random_name: domainName.split('.')[0],
75
+ random_subdomain: fulldomain.split('.')[0],
76
+ random_tld: domainName.split('.').pop(),
77
+ backlinks_count: Math.floor(Math.random() * 1000),
78
+ creation_date: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toISOString(),
79
+ expiration_date: new Date(Date.now() + Math.floor(Math.random() * 10000000000)).toISOString(),
80
+ };
81
+ }