@20syldev/api 5.5.0 → 5.7.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 (147) hide show
  1. package/.prettierignore +5 -0
  2. package/README.md +204 -80
  3. package/dist/app.d.ts +2 -0
  4. package/dist/config/env.d.ts +21 -0
  5. package/dist/config/env.js +10 -2
  6. package/dist/config/env.js.map +1 -1
  7. package/dist/config/plans.d.ts +26 -0
  8. package/dist/config/versions.d.ts +18 -0
  9. package/dist/config/versions.js +6 -0
  10. package/dist/config/versions.js.map +1 -1
  11. package/dist/constants.d.ts +39 -0
  12. package/dist/constants.js +3 -1
  13. package/dist/constants.js.map +1 -1
  14. package/dist/middleware/cors.d.ts +2 -0
  15. package/dist/middleware/cors.js +2 -1
  16. package/dist/middleware/cors.js.map +1 -1
  17. package/dist/middleware/error.d.ts +4 -0
  18. package/dist/middleware/json.d.ts +2 -0
  19. package/dist/middleware/logger.d.ts +26 -0
  20. package/dist/middleware/logger.js +34 -1
  21. package/dist/middleware/logger.js.map +1 -1
  22. package/dist/middleware/ratelimit.d.ts +2 -0
  23. package/dist/middleware/version.d.ts +3 -0
  24. package/dist/middleware/version.js +2 -2
  25. package/dist/middleware/version.js.map +1 -1
  26. package/dist/modules/v3/algorithms.d.ts +82 -0
  27. package/dist/modules/v3/captcha.d.ts +8 -0
  28. package/dist/modules/v3/chat.d.ts +9 -0
  29. package/dist/modules/v3/chat.js +3 -3
  30. package/dist/modules/v3/chat.js.map +1 -1
  31. package/dist/modules/v3/color.d.ts +6 -0
  32. package/dist/modules/v3/convert.d.ts +10 -0
  33. package/dist/modules/v3/domain.d.ts +6 -0
  34. package/dist/modules/v3/hash.d.ts +8 -0
  35. package/dist/modules/v3/hyperplanning.d.ts +9 -0
  36. package/dist/modules/v3/levenshtein.d.ts +9 -0
  37. package/dist/modules/v3/personal.d.ts +6 -0
  38. package/dist/modules/v3/qrcode.d.ts +8 -0
  39. package/dist/modules/v3/tic_tac_toe.d.ts +9 -0
  40. package/dist/modules/v3/tic_tac_toe.js +3 -3
  41. package/dist/modules/v3/tic_tac_toe.js.map +1 -1
  42. package/dist/modules/v3/time.d.ts +12 -0
  43. package/dist/modules/v3/token.d.ts +9 -0
  44. package/dist/modules/v3/username.d.ts +6 -0
  45. package/dist/modules/v3/utils.d.ts +50 -0
  46. package/dist/modules/v3.d.ts +15 -0
  47. package/dist/modules/v4/address.d.ts +20 -0
  48. package/dist/modules/v4/agent.d.ts +30 -0
  49. package/dist/modules/v4/algorithms.d.ts +90 -0
  50. package/dist/modules/v4/avatar.d.ts +23 -0
  51. package/dist/modules/v4/barcode.d.ts +27 -0
  52. package/dist/modules/v4/captcha.d.ts +22 -0
  53. package/dist/modules/v4/chat.d.ts +21 -0
  54. package/dist/modules/v4/chat.js +3 -3
  55. package/dist/modules/v4/chat.js.map +1 -1
  56. package/dist/modules/v4/color.d.ts +16 -0
  57. package/dist/modules/v4/convert.d.ts +15 -0
  58. package/dist/modules/v4/credit.d.ts +22 -0
  59. package/dist/modules/v4/cron.d.ts +17 -0
  60. package/dist/modules/v4/dice.d.ts +16 -0
  61. package/dist/modules/v4/domain.d.ts +6 -0
  62. package/dist/modules/v4/encode.d.ts +81 -0
  63. package/dist/modules/v4/geo.d.ts +30 -0
  64. package/dist/modules/v4/hash.d.ts +15 -0
  65. package/dist/modules/v4/hyperplanning.d.ts +19 -0
  66. package/dist/modules/v4/ip.d.ts +19 -0
  67. package/dist/modules/v4/levenshtein.d.ts +13 -0
  68. package/dist/modules/v4/palette.d.ts +19 -0
  69. package/dist/modules/v4/password.d.ts +25 -0
  70. package/dist/modules/v4/personal.d.ts +6 -0
  71. package/dist/modules/v4/placeholder.d.ts +30 -0
  72. package/dist/modules/v4/qrcode.d.ts +25 -0
  73. package/dist/modules/v4/regex.d.ts +23 -0
  74. package/dist/modules/v4/statistics.d.ts +20 -0
  75. package/dist/modules/v4/text.d.ts +43 -0
  76. package/dist/modules/v4/tic_tac_toe.d.ts +19 -0
  77. package/dist/modules/v4/tic_tac_toe.js +3 -3
  78. package/dist/modules/v4/tic_tac_toe.js.map +1 -1
  79. package/dist/modules/v4/time.d.ts +15 -0
  80. package/dist/modules/v4/token.d.ts +9 -0
  81. package/dist/modules/v4/username.d.ts +6 -0
  82. package/dist/modules/v4/validate.d.ts +34 -0
  83. package/dist/modules/v4.d.ts +32 -0
  84. package/dist/modules/v5/address.d.ts +5 -0
  85. package/dist/modules/v5/algorithms.d.ts +9 -0
  86. package/dist/modules/v5/asymmetric.d.ts +26 -0
  87. package/dist/modules/v5/barcode.d.ts +27 -0
  88. package/dist/modules/v5/case.d.ts +10 -0
  89. package/dist/modules/v5/chart.d.ts +53 -0
  90. package/dist/modules/v5/chat.d.ts +21 -0
  91. package/dist/modules/v5/chat.js +3 -3
  92. package/dist/modules/v5/chat.js.map +1 -1
  93. package/dist/modules/v5/csv.d.ts +29 -0
  94. package/dist/modules/v5/csv.js +143 -0
  95. package/dist/modules/v5/csv.js.map +1 -0
  96. package/dist/modules/v5/evaluate.d.ts +14 -0
  97. package/dist/modules/v5/jwt.d.ts +11 -0
  98. package/dist/modules/v5/matrix.d.ts +77 -0
  99. package/dist/modules/v5/otp.d.ts +30 -0
  100. package/dist/modules/v5/symmetric.d.ts +15 -0
  101. package/dist/modules/v5/text.d.ts +5 -0
  102. package/dist/modules/v5/tic_tac_toe.d.ts +19 -0
  103. package/dist/modules/v5/tic_tac_toe.js +3 -3
  104. package/dist/modules/v5/tic_tac_toe.js.map +1 -1
  105. package/dist/modules/v5/url.d.ts +18 -0
  106. package/dist/modules/v5/url.js +51 -0
  107. package/dist/modules/v5/url.js.map +1 -0
  108. package/dist/modules/v5.d.ts +17 -0
  109. package/dist/modules/v5.js +2 -0
  110. package/dist/modules/v5.js.map +1 -1
  111. package/dist/routes/delete.d.ts +2 -0
  112. package/dist/routes/delete.js +2 -2
  113. package/dist/routes/delete.js.map +1 -1
  114. package/dist/routes/get.d.ts +2 -0
  115. package/dist/routes/get.js +104 -82
  116. package/dist/routes/get.js.map +1 -1
  117. package/dist/routes/index.d.ts +2 -0
  118. package/dist/routes/index.js +8 -4
  119. package/dist/routes/index.js.map +1 -1
  120. package/dist/routes/patch.d.ts +2 -0
  121. package/dist/routes/patch.js +1 -1
  122. package/dist/routes/patch.js.map +1 -1
  123. package/dist/routes/post.d.ts +2 -0
  124. package/dist/routes/post.js +54 -29
  125. package/dist/routes/post.js.map +1 -1
  126. package/dist/storage/index.d.ts +4 -0
  127. package/dist/types/storage.d.ts +49 -0
  128. package/dist/utils/colors.d.ts +44 -0
  129. package/dist/utils/helpers.d.ts +55 -0
  130. package/dist/utils/response.d.ts +9 -0
  131. package/dist/utils/response.js +2 -4
  132. package/dist/utils/response.js.map +1 -1
  133. package/package.json +17 -16
  134. package/robots.txt +74 -0
  135. package/src/favicon.ico +0 -0
  136. package/dist/middleware/connection.js +0 -23
  137. package/dist/middleware/connection.js.map +0 -1
  138. package/dist/modules/v4/colors.js +0 -54
  139. package/dist/modules/v4/colors.js.map +0 -1
  140. package/dist/modules/v4/utils.js +0 -26
  141. package/dist/modules/v4/utils.js.map +0 -1
  142. package/dist/modules/v5/diff.js +0 -52
  143. package/dist/modules/v5/diff.js.map +0 -1
  144. package/dist/modules/v5/read.js +0 -39
  145. package/dist/modules/v5/read.js.map +0 -1
  146. package/dist/utils/version.js +0 -3
  147. package/dist/utils/version.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { Router } from 'express';
2
+ import { env } from '../config/env.js';
2
3
  import { versions } from '../config/versions.js';
3
- import { DOCS_URL } from '../constants.js';
4
4
  import { chatStorage } from '../storage/index.js';
5
5
  import { since } from '../utils/helpers.js';
6
6
  import { error } from '../utils/response.js';
@@ -8,7 +8,7 @@ const router = Router();
8
8
  const postOnly = (name) => (req, res) => {
9
9
  const available = versions[req.version]?.endpoints.post.some((e) => e.name === name);
10
10
  if (!available) {
11
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/${name}`);
11
+ error(res, 404, `Endpoint not available in ${req.version}.`);
12
12
  return;
13
13
  }
14
14
  error(res, 405, 'This endpoint only supports POST requests.');
@@ -41,7 +41,7 @@ router.get('/:version', (req, res) => {
41
41
  }, {});
42
42
  res.jsonResponse({
43
43
  version,
44
- documentation: `${DOCS_URL}/${version}`,
44
+ ...(env.DOCS_URL ? { documentation: `${env.DOCS_URL}/${version}` } : {}),
45
45
  endpoints,
46
46
  });
47
47
  });
@@ -51,12 +51,12 @@ router.get('/:version/address', (req, res) => {
51
51
  const { version } = req.params;
52
52
  const addressFn = req.module.address;
53
53
  if (!addressFn) {
54
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/address`);
54
+ error(res, 404, `Endpoint not available in ${version}.`);
55
55
  return;
56
56
  }
57
57
  const parsedCount = count !== undefined ? parseInt(count, 10) : 1;
58
58
  if (isNaN(parsedCount)) {
59
- error(res, 400, 'Please provide a valid count (&count={n})', `${version}/address`);
59
+ error(res, 400, 'Please provide a valid count (&count={n})');
60
60
  return;
61
61
  }
62
62
  try {
@@ -64,7 +64,7 @@ router.get('/:version/address', (req, res) => {
64
64
  res.jsonResponse(result);
65
65
  }
66
66
  catch (err) {
67
- error(res, 400, err.message, `${req.version}/address`);
67
+ error(res, 400, err.message);
68
68
  }
69
69
  });
70
70
  // Parse a User-Agent string
@@ -72,7 +72,7 @@ router.get('/:version/agent', (req, res) => {
72
72
  const ua = req.query.ua ?? req.headers['user-agent'] ?? '';
73
73
  const agentFn = req.module.agent;
74
74
  if (!agentFn) {
75
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/agent`);
75
+ error(res, 404, `Endpoint not available in ${req.version}.`);
76
76
  return;
77
77
  }
78
78
  try {
@@ -80,16 +80,15 @@ router.get('/:version/agent', (req, res) => {
80
80
  res.jsonResponse(result);
81
81
  }
82
82
  catch (err) {
83
- error(res, 400, err.message, `${req.version}/agent`);
83
+ error(res, 400, err.message);
84
84
  }
85
85
  });
86
86
  // Algorithms
87
87
  router.get('/:version/algorithms', (req, res) => {
88
88
  const { method, value, value2 } = req.query;
89
- const { version } = req.params;
90
89
  const algorithms = req.module.algorithms;
91
90
  if (!algorithms || !method || !Object.hasOwn(algorithms, method)) {
92
- error(res, 400, 'Please provide a valid algorithm (?method={algorithm})', `${version}/algorithms`);
91
+ error(res, 400, 'Please provide a valid algorithm (?method={algorithm})');
93
92
  return;
94
93
  }
95
94
  try {
@@ -97,7 +96,7 @@ router.get('/:version/algorithms', (req, res) => {
97
96
  res.jsonResponse({ answer });
98
97
  }
99
98
  catch (err) {
100
- error(res, 400, err.message, `${req.version}/algorithms`);
99
+ error(res, 400, err.message);
101
100
  }
102
101
  });
103
102
  // GET asymmetric error
@@ -108,11 +107,11 @@ router.get('/:version/case', (req, res) => {
108
107
  const { version } = req.params;
109
108
  const caseConvertFn = req.module.caseConvert;
110
109
  if (!caseConvertFn) {
111
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/case`);
110
+ error(res, 404, `Endpoint not available in ${version}.`);
112
111
  return;
113
112
  }
114
113
  if (!text || typeof text !== 'string') {
115
- error(res, 400, 'Please provide a text (?text={text})', `${version}/case`);
114
+ error(res, 400, 'Please provide a text (?text={text})');
116
115
  return;
117
116
  }
118
117
  try {
@@ -120,20 +119,20 @@ router.get('/:version/case', (req, res) => {
120
119
  res.jsonResponse(result);
121
120
  }
122
121
  catch (err) {
123
- error(res, 400, err.message, `${req.version}/case`);
122
+ error(res, 400, err.message);
124
123
  }
125
124
  });
126
125
  // Generate an identicon or pixel-art avatar from a seed
127
126
  router.get('/:version/avatar', (req, res) => {
128
127
  const avatarFn = req.module.avatar;
129
128
  if (!avatarFn) {
130
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/avatar`);
129
+ error(res, 404, `Endpoint not available in ${req.version}.`);
131
130
  return;
132
131
  }
133
132
  const { seed, size, type, bg, format } = req.query;
134
133
  const parsedSize = size !== undefined ? parseInt(size, 10) : undefined;
135
134
  if (parsedSize !== undefined && isNaN(parsedSize)) {
136
- error(res, 400, 'Please provide a valid size (&size={50-2000})', `${req.version}/avatar`);
135
+ error(res, 400, 'Please provide a valid size (&size={50-2000})');
137
136
  return;
138
137
  }
139
138
  try {
@@ -147,25 +146,25 @@ router.get('/:version/avatar', (req, res) => {
147
146
  res.type(contentType).send(body);
148
147
  }
149
148
  catch (err) {
150
- error(res, 400, err.message, `${req.version}/avatar`);
149
+ error(res, 400, err.message);
151
150
  }
152
151
  });
153
152
  // Generate a barcode image
154
153
  router.get('/:version/barcode', (req, res) => {
155
154
  const barcodeFn = req.module.barcode;
156
155
  if (!barcodeFn) {
157
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/barcode`);
156
+ error(res, 404, `Endpoint not available in ${req.version}.`);
158
157
  return;
159
158
  }
160
159
  const { data, type, width, height, format, color, bg } = req.query;
161
160
  if (!data) {
162
- error(res, 400, 'Please provide data to encode (?data={string})', `${req.version}/barcode`);
161
+ error(res, 400, 'Please provide data to encode (?data={string})');
163
162
  return;
164
163
  }
165
164
  const parsedWidth = width !== undefined ? parseInt(width, 10) : undefined;
166
165
  const parsedHeight = height !== undefined ? parseInt(height, 10) : undefined;
167
166
  if ((parsedWidth !== undefined && isNaN(parsedWidth)) || (parsedHeight !== undefined && isNaN(parsedHeight))) {
168
- error(res, 400, 'Please provide valid dimensions (&width={px}&height={px})', `${req.version}/barcode`);
167
+ error(res, 400, 'Please provide valid dimensions (&width={px}&height={px})');
169
168
  return;
170
169
  }
171
170
  try {
@@ -181,7 +180,7 @@ router.get('/:version/barcode', (req, res) => {
181
180
  res.type(contentType).send(body);
182
181
  }
183
182
  catch (err) {
184
- error(res, 400, err.message, `${req.version}/barcode`);
183
+ error(res, 400, err.message);
185
184
  }
186
185
  });
187
186
  // Generate captcha
@@ -204,7 +203,7 @@ router.get('/:version/captcha', (req, res) => {
204
203
  else {
205
204
  const text = req.query.text;
206
205
  if (!text) {
207
- error(res, 400, 'Please provide a valid argument (?text={text})', `${req.version}/captcha`);
206
+ error(res, 400, 'Please provide a valid argument (?text={text})');
208
207
  return;
209
208
  }
210
209
  const result = req.module.captcha(text);
@@ -212,7 +211,7 @@ router.get('/:version/captcha', (req, res) => {
212
211
  }
213
212
  }
214
213
  catch (err) {
215
- error(res, 400, err.message, `${req.version}/captcha`);
214
+ error(res, 400, err.message);
216
215
  }
217
216
  });
218
217
  // GET chart error
@@ -247,22 +246,22 @@ router.get('/:version/color', (req, res) => {
247
246
  }
248
247
  }
249
248
  catch (err) {
250
- error(res, 400, err.message, `${req.version}/color`);
249
+ error(res, 400, err.message);
251
250
  }
252
251
  });
253
252
  // Convert units
254
253
  router.get('/:version/convert', (req, res) => {
255
254
  const { value, from, to } = req.query;
256
255
  if (!value || isNaN(Number(value))) {
257
- error(res, 400, 'Please provide a valid value (?value={value})', `${req.version}/convert`);
256
+ error(res, 400, 'Please provide a valid value (?value={value})');
258
257
  return;
259
258
  }
260
259
  if (!from) {
261
- error(res, 400, 'Please provide a valid source unit (&from={unit})', `${req.version}/convert`);
260
+ error(res, 400, 'Please provide a valid source unit (&from={unit})');
262
261
  return;
263
262
  }
264
263
  if (!to) {
265
- error(res, 400, 'Please provide a valid target unit (&to={unit})', `${req.version}/convert`);
264
+ error(res, 400, 'Please provide a valid target unit (&to={unit})');
266
265
  return;
267
266
  }
268
267
  try {
@@ -277,7 +276,7 @@ router.get('/:version/convert', (req, res) => {
277
276
  }
278
277
  }
279
278
  catch (err) {
280
- error(res, 400, err.message, `${req.version}/convert`);
279
+ error(res, 400, err.message);
281
280
  }
282
281
  });
283
282
  // Generate fictitious credit card numbers
@@ -285,7 +284,7 @@ router.get('/:version/credit', (req, res) => {
285
284
  const creditFn = req.module
286
285
  .credit;
287
286
  if (!creditFn) {
288
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/credit`);
287
+ error(res, 404, `Endpoint not available in ${req.version}.`);
289
288
  return;
290
289
  }
291
290
  const { brand, count, format } = req.query;
@@ -294,7 +293,7 @@ router.get('/:version/credit', (req, res) => {
294
293
  res.jsonResponse(result);
295
294
  }
296
295
  catch (err) {
297
- error(res, 400, err.message, `${req.version}/credit`);
296
+ error(res, 400, err.message);
298
297
  }
299
298
  });
300
299
  // Parse a cron expression and compute next execution dates
@@ -303,16 +302,16 @@ router.get('/:version/cron', (req, res) => {
303
302
  const { version } = req.params;
304
303
  const cronFn = req.module.cron;
305
304
  if (!cronFn) {
306
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/cron`);
305
+ error(res, 404, `Endpoint not available in ${version}.`);
307
306
  return;
308
307
  }
309
308
  if (!expr) {
310
- error(res, 400, 'Please provide a cron expression (?expr=* * * * *)', `${version}/cron`);
309
+ error(res, 400, 'Please provide a cron expression (?expr=* * * * *)');
311
310
  return;
312
311
  }
313
312
  const parsedCount = count !== undefined ? parseInt(count, 10) : 5;
314
313
  if (isNaN(parsedCount)) {
315
- error(res, 400, 'Please provide a valid count (&count={n})', `${version}/cron`);
314
+ error(res, 400, 'Please provide a valid count (&count={n})');
316
315
  return;
317
316
  }
318
317
  try {
@@ -320,7 +319,7 @@ router.get('/:version/cron', (req, res) => {
320
319
  res.jsonResponse(result);
321
320
  }
322
321
  catch (err) {
323
- error(res, 400, err.message, `${req.version}/cron`);
322
+ error(res, 400, err.message);
324
323
  }
325
324
  });
326
325
  // RPG Dice roller
@@ -329,11 +328,11 @@ router.get('/:version/dice', (req, res) => {
329
328
  const { version } = req.params;
330
329
  const dice = req.module.dice;
331
330
  if (!dice) {
332
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/dice`);
331
+ error(res, 404, `Endpoint not available in ${version}.`);
333
332
  return;
334
333
  }
335
334
  if (!roll) {
336
- error(res, 400, 'Please provide a roll notation (?roll=2d6+3)', `${version}/dice`);
335
+ error(res, 400, 'Please provide a roll notation (?roll=2d6+3)');
337
336
  return;
338
337
  }
339
338
  try {
@@ -341,7 +340,7 @@ router.get('/:version/dice', (req, res) => {
341
340
  res.jsonResponse(result);
342
341
  }
343
342
  catch (err) {
344
- error(res, 400, err.message, `${req.version}/dice`);
343
+ error(res, 400, err.message);
345
344
  }
346
345
  });
347
346
  // Generate domain informations
@@ -351,7 +350,7 @@ router.get('/:version/domain', (req, res) => {
351
350
  res.jsonResponse(result);
352
351
  }
353
352
  catch (err) {
354
- error(res, 400, err.message, `${req.version}/domain`);
353
+ error(res, 400, err.message);
355
354
  }
356
355
  });
357
356
  // Encode / decode text
@@ -360,11 +359,11 @@ router.get('/:version/encode', (req, res) => {
360
359
  const { version } = req.params;
361
360
  const encode = req.module.encode;
362
361
  if (!encode) {
363
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/encode`);
362
+ error(res, 404, `Endpoint not available in ${version}.`);
364
363
  return;
365
364
  }
366
365
  if (!method || !Object.hasOwn(encode, method)) {
367
- error(res, 400, 'Please provide a valid method (?method={method})', `${version}/encode`);
366
+ error(res, 400, 'Please provide a valid method (?method={method})');
368
367
  return;
369
368
  }
370
369
  try {
@@ -372,7 +371,7 @@ router.get('/:version/encode', (req, res) => {
372
371
  res.jsonResponse({ method, result });
373
372
  }
374
373
  catch (err) {
375
- error(res, 400, err.message, `${req.version}/encode`);
374
+ error(res, 400, err.message);
376
375
  }
377
376
  });
378
377
  // Evaluate a math expression
@@ -381,11 +380,11 @@ router.get('/:version/evaluate', (req, res) => {
381
380
  const { version } = req.params;
382
381
  const evaluateFn = req.module.evaluate;
383
382
  if (!evaluateFn) {
384
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/evaluate`);
383
+ error(res, 404, `Endpoint not available in ${version}.`);
385
384
  return;
386
385
  }
387
386
  if (!expr || typeof expr !== 'string') {
388
- error(res, 400, 'Please provide a math expression (?expr={expression})', `${version}/evaluate`);
387
+ error(res, 400, 'Please provide a math expression (?expr={expression})');
389
388
  return;
390
389
  }
391
390
  try {
@@ -393,7 +392,7 @@ router.get('/:version/evaluate', (req, res) => {
393
392
  res.jsonResponse(result);
394
393
  }
395
394
  catch (err) {
396
- error(res, 400, err.message, `${req.version}/evaluate`);
395
+ error(res, 400, err.message);
397
396
  }
398
397
  });
399
398
  // Geographic distance and bearing between two coordinates
@@ -402,11 +401,11 @@ router.get('/:version/geo', (req, res) => {
402
401
  const { version } = req.params;
403
402
  const geo = req.module.geo;
404
403
  if (!geo) {
405
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/geo`);
404
+ error(res, 404, `Endpoint not available in ${version}.`);
406
405
  return;
407
406
  }
408
407
  if (lat1 === undefined || lon1 === undefined || lat2 === undefined || lon2 === undefined) {
409
- error(res, 400, 'Please provide lat1, lon1, lat2 and lon2', `${version}/geo`);
408
+ error(res, 400, 'Please provide lat1, lon1, lat2 and lon2');
410
409
  return;
411
410
  }
412
411
  try {
@@ -414,7 +413,7 @@ router.get('/:version/geo', (req, res) => {
414
413
  res.jsonResponse(result);
415
414
  }
416
415
  catch (err) {
417
- error(res, 400, err.message, `${req.version}/geo`);
416
+ error(res, 400, err.message);
418
417
  }
419
418
  });
420
419
  // GET hash error
@@ -449,9 +448,9 @@ router.get('/:version/infos', (req, res) => {
449
448
  res.jsonResponse({
450
449
  endpoints: new Set(paths).size,
451
450
  last_version: Object.keys(versions).pop(),
452
- documentation: DOCS_URL,
453
- github: 'https://github.com/20syldev/api',
454
- creation: 'November 25th 2024',
451
+ ...(env.DOCS_URL ? { documentation: env.DOCS_URL } : {}),
452
+ ...(env.REPO_URL ? { github: env.REPO_URL } : {}),
453
+ ...(env.INSTANCE_CREATED ? { creation: env.INSTANCE_CREATED } : {}),
455
454
  });
456
455
  });
457
456
  // Analyze an IP address
@@ -459,7 +458,7 @@ router.get('/:version/ip', (req, res) => {
459
458
  const address = req.query.address ?? req.ip ?? '';
460
459
  const ipFn = req.module.ip;
461
460
  if (!ipFn) {
462
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/ip`);
461
+ error(res, 404, `Endpoint not available in ${req.version}.`);
463
462
  return;
464
463
  }
465
464
  try {
@@ -467,7 +466,7 @@ router.get('/:version/ip', (req, res) => {
467
466
  res.jsonResponse(result);
468
467
  }
469
468
  catch (err) {
470
- error(res, 400, err.message, `${req.version}/ip`);
469
+ error(res, 400, err.message);
471
470
  }
472
471
  });
473
472
  // GET jwt error
@@ -476,11 +475,11 @@ router.get('/:version/jwt', postOnly('jwt'));
476
475
  router.get('/:version/levenshtein', (req, res) => {
477
476
  const { str1, str2 } = req.query;
478
477
  if (!str1 || typeof str1 !== 'string') {
479
- error(res, 400, 'Please provide a first string (?str1={string})', `${req.version}/levenshtein`);
478
+ error(res, 400, 'Please provide a first string (?str1={string})');
480
479
  return;
481
480
  }
482
481
  if (!str2 || typeof str2 !== 'string') {
483
- error(res, 400, 'Please provide a second string (&str2={string})', `${req.version}/levenshtein`);
482
+ error(res, 400, 'Please provide a second string (&str2={string})');
484
483
  return;
485
484
  }
486
485
  try {
@@ -488,7 +487,7 @@ router.get('/:version/levenshtein', (req, res) => {
488
487
  res.jsonResponse(result);
489
488
  }
490
489
  catch (err) {
491
- error(res, 400, err.message, `${req.version}/levenshtein`);
490
+ error(res, 400, err.message);
492
491
  }
493
492
  });
494
493
  // GET matrix error
@@ -501,15 +500,15 @@ router.get('/:version/palette', (req, res) => {
501
500
  const { version } = req.params;
502
501
  const palette = req.module.palette;
503
502
  if (!palette) {
504
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/palette`);
503
+ error(res, 404, `Endpoint not available in ${version}.`);
505
504
  return;
506
505
  }
507
506
  if (!color) {
508
- error(res, 400, 'Please provide a base color (?color=#ff6600)', `${version}/palette`);
507
+ error(res, 400, 'Please provide a base color (?color=#ff6600)');
509
508
  return;
510
509
  }
511
510
  if (!type) {
512
- error(res, 400, 'Please provide a palette type (&type=complementary)', `${version}/palette`);
511
+ error(res, 400, 'Please provide a palette type (&type=complementary)');
513
512
  return;
514
513
  }
515
514
  try {
@@ -517,7 +516,7 @@ router.get('/:version/palette', (req, res) => {
517
516
  res.jsonResponse(result);
518
517
  }
519
518
  catch (err) {
520
- error(res, 400, err.message, `${req.version}/palette`);
519
+ error(res, 400, err.message);
521
520
  }
522
521
  });
523
522
  // Generate a password or passphrase
@@ -526,7 +525,7 @@ router.get('/:version/password', (req, res) => {
526
525
  const { version } = req.params;
527
526
  const passwordFn = req.module.password;
528
527
  if (!passwordFn) {
529
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/password`);
528
+ error(res, 404, `Endpoint not available in ${version}.`);
530
529
  return;
531
530
  }
532
531
  const parseBool = (v, def) => (v === undefined ? def : v !== 'false');
@@ -543,7 +542,7 @@ router.get('/:version/password', (req, res) => {
543
542
  res.jsonResponse(result);
544
543
  }
545
544
  catch (err) {
546
- error(res, 400, err.message, `${req.version}/password`);
545
+ error(res, 400, err.message);
547
546
  }
548
547
  });
549
548
  // Generate personal data
@@ -553,7 +552,7 @@ router.get('/:version/personal', (req, res) => {
553
552
  res.jsonResponse(result);
554
553
  }
555
554
  catch (err) {
556
- error(res, 400, err.message, `${req.version}/personal`);
555
+ error(res, 400, err.message);
557
556
  }
558
557
  });
559
558
  // Generate a placeholder image or skeleton
@@ -562,7 +561,7 @@ router.get('/:version/placeholder', (req, res) => {
562
561
  const { version } = req.params;
563
562
  const placeholder = req.module.placeholder;
564
563
  if (!placeholder) {
565
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/placeholder`);
564
+ error(res, 404, `Endpoint not available in ${version}.`);
566
565
  return;
567
566
  }
568
567
  try {
@@ -570,14 +569,14 @@ router.get('/:version/placeholder', (req, res) => {
570
569
  res.type(result.contentType).send(result.body);
571
570
  }
572
571
  catch (err) {
573
- error(res, 400, err.message, `${req.version}/placeholder`);
572
+ error(res, 400, err.message);
574
573
  }
575
574
  });
576
575
  // Generate QR Code
577
576
  router.get('/:version/qrcode', async (req, res) => {
578
577
  const { url } = req.query;
579
578
  if (!url) {
580
- error(res, 400, 'Please provide a valid url (?url={URL})', `${req.version}/qrcode`);
579
+ error(res, 400, 'Please provide a valid url (?url={URL})');
581
580
  return;
582
581
  }
583
582
  try {
@@ -609,7 +608,7 @@ router.get('/:version/qrcode', async (req, res) => {
609
608
  }
610
609
  }
611
610
  catch (err) {
612
- error(res, 400, err.message, `${req.version}/qrcode`);
611
+ error(res, 400, err.message);
613
612
  }
614
613
  });
615
614
  // Test a regex pattern against a text
@@ -618,15 +617,15 @@ router.get('/:version/regex', (req, res) => {
618
617
  const { version } = req.params;
619
618
  const regexFn = req.module.regex;
620
619
  if (!regexFn) {
621
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/regex`);
620
+ error(res, 404, `Endpoint not available in ${version}.`);
622
621
  return;
623
622
  }
624
623
  if (!pattern) {
625
- error(res, 400, 'Please provide a pattern (?pattern={regex})', `${version}/regex`);
624
+ error(res, 400, 'Please provide a pattern (?pattern={regex})');
626
625
  return;
627
626
  }
628
627
  if (!text) {
629
- error(res, 400, 'Please provide a text (&text={string})', `${version}/regex`);
628
+ error(res, 400, 'Please provide a text (&text={string})');
630
629
  return;
631
630
  }
632
631
  try {
@@ -634,7 +633,7 @@ router.get('/:version/regex', (req, res) => {
634
633
  res.jsonResponse(result);
635
634
  }
636
635
  catch (err) {
637
- error(res, 400, err.message, `${req.version}/regex`);
636
+ error(res, 400, err.message);
638
637
  }
639
638
  });
640
639
  // Statistics on a list of numbers
@@ -643,11 +642,11 @@ router.get('/:version/statistics', (req, res) => {
643
642
  const { version } = req.params;
644
643
  const statistics = req.module.statistics;
645
644
  if (!statistics) {
646
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/statistics`);
645
+ error(res, 404, `Endpoint not available in ${version}.`);
647
646
  return;
648
647
  }
649
648
  if (!values) {
650
- error(res, 400, 'Please provide a list of values (?values=1,2,3)', `${version}/statistics`);
649
+ error(res, 400, 'Please provide a list of values (?values=1,2,3)');
651
650
  return;
652
651
  }
653
652
  try {
@@ -655,7 +654,7 @@ router.get('/:version/statistics', (req, res) => {
655
654
  res.jsonResponse(result);
656
655
  }
657
656
  catch (err) {
658
- error(res, 400, err.message, `${req.version}/statistics`);
657
+ error(res, 400, err.message);
659
658
  }
660
659
  });
661
660
  // GET symmetric error
@@ -666,11 +665,11 @@ router.get('/:version/text', (req, res) => {
666
665
  const { version } = req.params;
667
666
  const textMod = req.module.text;
668
667
  if (!textMod) {
669
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/text`);
668
+ error(res, 404, `Endpoint not available in ${version}.`);
670
669
  return;
671
670
  }
672
671
  if (!method || !Object.hasOwn(textMod, method)) {
673
- error(res, 400, 'Please provide a valid method (?method={slug|stats|lorem|number})', `${version}/text`);
672
+ error(res, 400, 'Please provide a valid method (?method={slug|stats|lorem|number})');
674
673
  return;
675
674
  }
676
675
  try {
@@ -692,7 +691,7 @@ router.get('/:version/text', (req, res) => {
692
691
  res.jsonResponse({ method, result });
693
692
  }
694
693
  catch (err) {
695
- error(res, 400, err.message, `${req.version}/text`);
694
+ error(res, 400, err.message);
696
695
  }
697
696
  });
698
697
  // GET tic-tac-toe errors
@@ -708,11 +707,34 @@ router.get('/:version/time', (req, res) => {
708
707
  res.jsonResponse(time);
709
708
  }
710
709
  catch (err) {
711
- error(res, 400, err.message, `${req.version}/time`);
710
+ error(res, 400, err.message);
712
711
  }
713
712
  });
713
+ // GET csv error
714
+ router.get('/:version/csv', postOnly('csv'));
714
715
  // GET token error
715
716
  router.get('/:version/token', postOnly('token'));
717
+ // Parse a URL into its components
718
+ router.get('/:version/url', (req, res) => {
719
+ const { url } = req.query;
720
+ const { version } = req.params;
721
+ const parseUrlFn = req.module.parseUrl;
722
+ if (!parseUrlFn) {
723
+ error(res, 404, `Endpoint not available in ${version}.`);
724
+ return;
725
+ }
726
+ if (!url || typeof url !== 'string') {
727
+ error(res, 400, 'Please provide a URL (?url={URL})');
728
+ return;
729
+ }
730
+ try {
731
+ const result = parseUrlFn(url);
732
+ res.jsonResponse(result);
733
+ }
734
+ catch (err) {
735
+ error(res, 400, err.message);
736
+ }
737
+ });
716
738
  // Generate username
717
739
  router.get('/:version/username', (req, res) => {
718
740
  try {
@@ -720,7 +742,7 @@ router.get('/:version/username', (req, res) => {
720
742
  res.jsonResponse(result);
721
743
  }
722
744
  catch (err) {
723
- error(res, 400, err.message, `${req.version}/username`);
745
+ error(res, 400, err.message);
724
746
  }
725
747
  });
726
748
  // Validate data (luhn, iban, email)
@@ -729,15 +751,15 @@ router.get('/:version/validate', (req, res) => {
729
751
  const { version } = req.params;
730
752
  const validate = req.module.validate;
731
753
  if (!validate) {
732
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/validate`);
754
+ error(res, 404, `Endpoint not available in ${version}.`);
733
755
  return;
734
756
  }
735
757
  if (!type || !Object.hasOwn(validate, type)) {
736
- error(res, 400, 'Please provide a valid type (?type={luhn|iban|email})', `${version}/validate`);
758
+ error(res, 400, 'Please provide a valid type (?type={luhn|iban|email})');
737
759
  return;
738
760
  }
739
761
  if (!value) {
740
- error(res, 400, 'Please provide a value (&value={value})', `${version}/validate`);
762
+ error(res, 400, 'Please provide a value (&value={value})');
741
763
  return;
742
764
  }
743
765
  try {
@@ -745,7 +767,7 @@ router.get('/:version/validate', (req, res) => {
745
767
  res.jsonResponse(result);
746
768
  }
747
769
  catch (err) {
748
- error(res, 400, err.message, `${req.version}/validate`);
770
+ error(res, 400, err.message);
749
771
  }
750
772
  });
751
773
  export default router;