@20syldev/api 3.5.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) 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/eslint.config.js +20 -0
  126. package/package.json +30 -15
  127. package/src/app.ts +44 -0
  128. package/src/config/env.ts +81 -0
  129. package/src/config/versions.ts +80 -0
  130. package/src/constants.ts +28 -0
  131. package/src/middleware/cors.ts +17 -0
  132. package/src/middleware/error.ts +7 -0
  133. package/src/middleware/json.ts +9 -0
  134. package/src/middleware/logger.ts +31 -0
  135. package/src/middleware/ratelimit.ts +66 -0
  136. package/src/middleware/version.ts +39 -0
  137. package/{modules → src/modules}/v3/algorithms.js +1 -1
  138. package/src/modules/v3/captcha.js +60 -0
  139. package/{modules → src/modules}/v3/chat.js +6 -4
  140. package/src/modules/v3/color.js +60 -0
  141. package/{modules → src/modules}/v3/convert.js +5 -5
  142. package/{modules → src/modules}/v3/domain.js +51 -4
  143. package/{modules → src/modules}/v3/hash.js +1 -1
  144. package/{modules → src/modules}/v3/hyperplanning.js +11 -10
  145. package/{modules → src/modules}/v3/levenshtein.js +3 -3
  146. package/{modules → src/modules}/v3/personal.js +20 -8
  147. package/{modules → src/modules}/v3/qrcode.js +1 -1
  148. package/{modules → src/modules}/v3/tic_tac_toe.js +24 -18
  149. package/{modules → src/modules}/v3/time.js +22 -11
  150. package/src/modules/v3/token.js +54 -0
  151. package/src/modules/v3/username.js +94 -0
  152. package/{modules → src/modules}/v3/utils.js +2 -2
  153. package/{modules → src/modules}/v3.js +1 -1
  154. package/src/modules/v4/algorithms.ts +155 -0
  155. package/src/modules/v4/captcha.ts +49 -0
  156. package/src/modules/v4/chat.ts +99 -0
  157. package/src/modules/v4/color.ts +64 -0
  158. package/src/modules/v4/convert.ts +38 -0
  159. package/src/modules/v4/domain.ts +81 -0
  160. package/src/modules/v4/hash.ts +9 -0
  161. package/src/modules/v4/hyperplanning.ts +58 -0
  162. package/src/modules/v4/levenshtein.ts +38 -0
  163. package/src/modules/v4/personal.ts +147 -0
  164. package/src/modules/v4/qrcode.ts +11 -0
  165. package/src/modules/v4/tic_tac_toe.ts +223 -0
  166. package/src/modules/v4/time.ts +92 -0
  167. package/src/modules/v4/token.ts +43 -0
  168. package/src/modules/v4/username.ts +89 -0
  169. package/src/modules/v4/utils.ts +38 -0
  170. package/src/modules/v4.ts +15 -0
  171. package/src/routes/get.ts +461 -0
  172. package/src/routes/index.ts +58 -0
  173. package/src/routes/post.ts +200 -0
  174. package/src/storage/index.ts +16 -0
  175. package/src/types/express.d.ts +17 -0
  176. package/src/types/storage.ts +48 -0
  177. package/src/utils/response.ts +11 -0
  178. package/tsconfig.json +17 -0
  179. package/app.js +0 -865
  180. package/modules/v3/username.js +0 -32
@@ -0,0 +1,58 @@
1
+ import { Router, type Request, type Response } from 'express';
2
+ import { versions } from '../config/versions.js';
3
+ import { ipLimits } from '../storage/index.js';
4
+ import { logger } from '../middleware/logger.js';
5
+ import { DOCS_URL, START_TIME } from '../constants.js';
6
+
7
+ const router = Router();
8
+
9
+ router.get('/', (req: Request, res: Response) => {
10
+ const base = `${req.protocol}://${req.get('host')}`;
11
+ const links = Object.keys(versions).reduce<Record<string, string>>((link, version) => {
12
+ link[version] = `${base}/${version}`;
13
+ return link;
14
+ }, {});
15
+
16
+ res.jsonResponse({
17
+ documentation: DOCS_URL,
18
+ latest: `${base}/latest`,
19
+ health: `${base}/health`,
20
+ logs: `${base}/logs`,
21
+ versions: links,
22
+ });
23
+ });
24
+
25
+ router.get('/health', (_req: Request, res: Response) => {
26
+ const mem = process.memoryUsage();
27
+
28
+ res.jsonResponse({
29
+ status: 'ok',
30
+ uptime: Math.floor((Date.now() - START_TIME) / 1000),
31
+ version: '4.0.0',
32
+ node: process.version,
33
+ memory: {
34
+ rss: `${(mem.rss / 1024 / 1024).toFixed(1)} MB`,
35
+ heap_used: `${(mem.heapUsed / 1024 / 1024).toFixed(1)} MB`,
36
+ heap_total: `${(mem.heapTotal / 1024 / 1024).toFixed(1)} MB`,
37
+ },
38
+ connections: Object.keys(ipLimits).length,
39
+ logs: logger.entries().length,
40
+ });
41
+ });
42
+
43
+ router.get('/logs', (_req: Request, res: Response) => {
44
+ res.jsonResponse(logger.entries());
45
+ });
46
+
47
+ router.get('/latest', (_req: Request, res: Response) => {
48
+ const latest = Object.keys(versions).pop()!;
49
+ res.redirect(`/${latest}`);
50
+ });
51
+
52
+ router.get('/latest/{*rest}', (req: Request, res: Response) => {
53
+ const latest = Object.keys(versions).pop()!;
54
+ const rest = (req.params as Record<string, string>).rest;
55
+ res.redirect(`/${latest}/${rest}`);
56
+ });
57
+
58
+ export default router;
@@ -0,0 +1,200 @@
1
+ import { Router, type Request, type Response } from 'express';
2
+ import { chatStorage, ticTacToeStorage } from '../storage/index.js';
3
+ import { MIN_TOKEN_LENGTH, MAX_TOKEN_LENGTH } from '../constants.js';
4
+ import { error } from '../utils/response.js';
5
+
6
+ const router = Router();
7
+
8
+ // Store chat messages
9
+ router.post('/:version/chat', (req: Request, res: Response) => {
10
+ const { username, message, timestamp, session, token } = (req.body as Record<string, string>) || {};
11
+
12
+ if (!username) {
13
+ error(res, 400, 'Please provide a username (?username={username})');
14
+ return;
15
+ }
16
+ if (!message) {
17
+ error(res, 400, 'Please provide a message (&message={message})');
18
+ return;
19
+ }
20
+ if (!session) {
21
+ error(res, 400, 'Please provide a valid session ID (&session={ID})');
22
+ return;
23
+ }
24
+
25
+ try {
26
+ const result = req.module.chat('message', {
27
+ username,
28
+ message,
29
+ timestamp,
30
+ session,
31
+ token,
32
+ storage: chatStorage,
33
+ });
34
+ res.jsonResponse(result);
35
+ } catch (err) {
36
+ error(res, 400, (err as Error).message);
37
+ }
38
+ });
39
+
40
+ // Display a private chat with a token
41
+ router.post('/:version/chat/private', (req: Request, res: Response) => {
42
+ const { username, token } = (req.body as Record<string, string>) || {};
43
+
44
+ if (!username) {
45
+ error(res, 400, 'Please provide a username (?username={username})');
46
+ return;
47
+ }
48
+ if (!token) {
49
+ error(res, 400, 'Please provide a valid token (&token={key}).');
50
+ return;
51
+ }
52
+
53
+ try {
54
+ const messages = req.module.chat('private', {
55
+ username,
56
+ token,
57
+ storage: chatStorage,
58
+ });
59
+ res.jsonResponse(messages);
60
+ } catch (err) {
61
+ error(res, 400, (err as Error).message);
62
+ }
63
+ });
64
+
65
+ // Generate hash
66
+ router.post('/:version/hash', (req: Request, res: Response) => {
67
+ const { text, method } = (req.body as Record<string, string>) || {};
68
+
69
+ if (!text) {
70
+ error(res, 400, 'Please provide a text (?text={text})', `${req.version}/hash`);
71
+ return;
72
+ }
73
+ if (!method) {
74
+ error(res, 400, 'Please provide a valid hash algorithm (&method={algorithm})', `${req.version}/hash`);
75
+ return;
76
+ }
77
+
78
+ try {
79
+ const result = req.module.hash(text, method);
80
+ res.jsonResponse(result);
81
+ } catch (err) {
82
+ error(res, 400, (err as Error).message, `${req.version}/hash`);
83
+ }
84
+ });
85
+
86
+ // Display a planning from an ICS file
87
+ router.post('/:version/hyperplanning', async (req: Request, res: Response) => {
88
+ const { url, detail } = (req.body as Record<string, string>) || {};
89
+
90
+ if (!url) {
91
+ error(res, 400, 'Please provide a valid ICS file URL (?url={URL})', `${req.version}/hyperplanning`);
92
+ return;
93
+ }
94
+
95
+ try {
96
+ const hyperplanning = await req.module.hyperplanning(url, detail);
97
+ res.jsonResponse(hyperplanning);
98
+ } catch (err) {
99
+ error(res, 400, (err as Error).message, `${req.version}/hyperplanning`);
100
+ }
101
+ });
102
+
103
+ // Store tic tac toe games
104
+ router.post('/:version/tic-tac-toe', (req: Request, res: Response) => {
105
+ const { username, move, session, game } = (req.body as Record<string, string>) || {};
106
+
107
+ if (!username) {
108
+ error(res, 400, 'Please provide a username (?username={username})');
109
+ return;
110
+ }
111
+ if (!move) {
112
+ error(res, 400, 'Please provide a valid move (&move={move})');
113
+ return;
114
+ }
115
+ if (!session) {
116
+ error(res, 400, 'Please provide a valid session ID (&session={ID})');
117
+ return;
118
+ }
119
+ if (!game) {
120
+ error(res, 400, 'Please provide a valid game ID (&game={ID})');
121
+ return;
122
+ }
123
+
124
+ try {
125
+ const result = req.module.tic_tac_toe('play', {
126
+ username,
127
+ move,
128
+ session,
129
+ game,
130
+ storage: ticTacToeStorage,
131
+ });
132
+ res.jsonResponse(result);
133
+ } catch (err) {
134
+ error(res, 400, (err as Error).message);
135
+ }
136
+ });
137
+
138
+ // Display a tic tac toe game with a token
139
+ router.post('/:version/tic-tac-toe/fetch', (req: Request, res: Response) => {
140
+ const { username, game } = (req.body as Record<string, string>) || {};
141
+ const privateGame = ((req.body as Record<string, unknown>) || {}).private as boolean | undefined;
142
+
143
+ if (!username) {
144
+ error(res, 400, 'Please provide a username (?username={username})');
145
+ return;
146
+ }
147
+
148
+ try {
149
+ const result = req.module.tic_tac_toe('fetch', {
150
+ username,
151
+ game,
152
+ private: privateGame,
153
+ storage: ticTacToeStorage,
154
+ });
155
+ res.jsonResponse(result);
156
+ } catch (err) {
157
+ error(res, 400, (err as Error).message);
158
+ }
159
+ });
160
+
161
+ // List public tic tac toe games
162
+ router.post('/:version/tic-tac-toe/list', (req: Request, res: Response) => {
163
+ try {
164
+ const result = req.module.tic_tac_toe('list', {
165
+ storage: ticTacToeStorage,
166
+ });
167
+ res.jsonResponse(result);
168
+ } catch (err) {
169
+ error(res, 400, (err as Error).message);
170
+ }
171
+ });
172
+
173
+ // Generate Token
174
+ router.post('/:version/token', (req: Request, res: Response) => {
175
+ const body = (req.body as Record<string, unknown>) || {};
176
+ const len = parseInt(String(body.len || 24), 10);
177
+ const type = body.type ? String(body.type).toLowerCase() : 'alpha';
178
+
179
+ if (isNaN(len) || len < 0) {
180
+ error(res, 400, 'Invalid number.', `${req.version}/token`);
181
+ return;
182
+ }
183
+ if (len > MAX_TOKEN_LENGTH) {
184
+ error(res, 400, 'Length cannot exceed 4096.', `${req.version}/token`);
185
+ return;
186
+ }
187
+ if (len < MIN_TOKEN_LENGTH) {
188
+ error(res, 400, 'Length cannot be less than 12.', `${req.version}/token`);
189
+ return;
190
+ }
191
+
192
+ try {
193
+ const token = req.module.token(len, type);
194
+ res.jsonResponse({ token });
195
+ } catch (err) {
196
+ error(res, 400, (err as Error).message, `${req.version}/token`);
197
+ }
198
+ });
199
+
200
+ export default router;
@@ -0,0 +1,16 @@
1
+ import type { ChatStorage, TicTacToeStorage, IpLimits } from '../types/storage.js';
2
+
3
+ export const ipLimits: IpLimits = {};
4
+
5
+ export const chatStorage: ChatStorage = {
6
+ messages: [],
7
+ privateChats: {},
8
+ sessions: {},
9
+ rateLimits: {},
10
+ };
11
+
12
+ export const ticTacToeStorage: TicTacToeStorage = {
13
+ games: {},
14
+ sessions: {},
15
+ rateLimits: {},
16
+ };
@@ -0,0 +1,17 @@
1
+ import type * as apiv3 from '../modules/v3.js';
2
+ import type * as apiv4 from '../modules/v4.js';
3
+
4
+ declare global {
5
+ namespace Express {
6
+ interface Request {
7
+ version: string;
8
+ latest: string;
9
+ endpoint: string;
10
+ module: typeof apiv3 | typeof apiv4;
11
+ }
12
+
13
+ interface Response {
14
+ jsonResponse: (data: unknown) => void;
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,48 @@
1
+ export interface LogEntry {
2
+ timestamp: string;
3
+ method: string;
4
+ url: string;
5
+ status: number;
6
+ duration: string;
7
+ platform: string | undefined;
8
+ }
9
+
10
+ export interface ChatMessage {
11
+ username: string;
12
+ message: string;
13
+ timestamp: string;
14
+ }
15
+
16
+ export interface ChatStorage {
17
+ messages: ChatMessage[];
18
+ privateChats: Record<string, ChatMessage[]>;
19
+ sessions: Record<string, { user: string; last: number }>;
20
+ rateLimits: Record<string, number[]>;
21
+ }
22
+
23
+ export interface TicTacToeMove {
24
+ username: string;
25
+ move: string;
26
+ session: string;
27
+ }
28
+
29
+ export interface TicTacToeGame {
30
+ moves: TicTacToeMove[];
31
+ players: string[];
32
+ private: boolean;
33
+ creation: number;
34
+ }
35
+
36
+ export interface TicTacToeStorage {
37
+ games: Record<string, TicTacToeGame>;
38
+ sessions: Record<string, { user: string; last: number }>;
39
+ rateLimits: Record<string, number[]>;
40
+ }
41
+
42
+ export interface IpLimits {
43
+ [ip: string]: {
44
+ [hour: string]: {
45
+ [minute: string]: number;
46
+ };
47
+ };
48
+ }
@@ -0,0 +1,11 @@
1
+ import type { Response } from 'express';
2
+ import { DOCS_URL, STATUS_MESSAGES } from '../constants.js';
3
+
4
+ export function error(res: Response, status: number, message: string, docPath?: string): void {
5
+ res.status(status).jsonResponse({
6
+ message: STATUS_MESSAGES[status] ?? 'Error',
7
+ error: message,
8
+ documentation: docPath ? `${DOCS_URL}/${docPath}` : DOCS_URL,
9
+ status: String(status),
10
+ });
11
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "allowJs": true,
7
+ "strict": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "outDir": "dist",
10
+ "rootDir": "src",
11
+ "declaration": false,
12
+ "sourceMap": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true
15
+ },
16
+ "include": ["src"]
17
+ }