@20syldev/api 5.6.0 → 5.8.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 (148) 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 +5 -0
  10. package/dist/config/versions.js.map +1 -1
  11. package/dist/constants.d.ts +45 -0
  12. package/dist/constants.js +6 -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/base.d.ts +16 -0
  89. package/dist/modules/v5/base.js +41 -0
  90. package/dist/modules/v5/base.js.map +1 -0
  91. package/dist/modules/v5/case.d.ts +10 -0
  92. package/dist/modules/v5/chart.d.ts +53 -0
  93. package/dist/modules/v5/chat.d.ts +21 -0
  94. package/dist/modules/v5/chat.js +3 -3
  95. package/dist/modules/v5/chat.js.map +1 -1
  96. package/dist/modules/v5/csv.d.ts +29 -0
  97. package/dist/modules/v5/diff.d.ts +20 -0
  98. package/dist/modules/v5/diff.js +81 -0
  99. package/dist/modules/v5/diff.js.map +1 -0
  100. package/dist/modules/v5/evaluate.d.ts +14 -0
  101. package/dist/modules/v5/jwt.d.ts +11 -0
  102. package/dist/modules/v5/matrix.d.ts +77 -0
  103. package/dist/modules/v5/otp.d.ts +30 -0
  104. package/dist/modules/v5/read.d.ts +20 -0
  105. package/dist/modules/v5/read.js +59 -0
  106. package/dist/modules/v5/read.js.map +1 -0
  107. package/dist/modules/v5/semver.d.ts +33 -0
  108. package/dist/modules/v5/semver.js +99 -0
  109. package/dist/modules/v5/semver.js.map +1 -0
  110. package/dist/modules/v5/symmetric.d.ts +15 -0
  111. package/dist/modules/v5/text.d.ts +5 -0
  112. package/dist/modules/v5/tic_tac_toe.d.ts +19 -0
  113. package/dist/modules/v5/tic_tac_toe.js +3 -3
  114. package/dist/modules/v5/tic_tac_toe.js.map +1 -1
  115. package/dist/modules/v5/url.d.ts +18 -0
  116. package/dist/modules/v5/url.js +12 -3
  117. package/dist/modules/v5/url.js.map +1 -1
  118. package/dist/modules/v5/uuid.d.ts +25 -0
  119. package/dist/modules/v5/uuid.js +40 -0
  120. package/dist/modules/v5/uuid.js.map +1 -0
  121. package/dist/modules/v5.d.ts +22 -0
  122. package/dist/modules/v5.js +5 -0
  123. package/dist/modules/v5.js.map +1 -1
  124. package/dist/routes/delete.d.ts +2 -0
  125. package/dist/routes/delete.js +2 -2
  126. package/dist/routes/delete.js.map +1 -1
  127. package/dist/routes/get.d.ts +2 -0
  128. package/dist/routes/get.js +152 -85
  129. package/dist/routes/get.js.map +1 -1
  130. package/dist/routes/index.d.ts +2 -0
  131. package/dist/routes/index.js +25 -5
  132. package/dist/routes/index.js.map +1 -1
  133. package/dist/routes/patch.d.ts +2 -0
  134. package/dist/routes/patch.js +1 -1
  135. package/dist/routes/patch.js.map +1 -1
  136. package/dist/routes/post.d.ts +2 -0
  137. package/dist/routes/post.js +80 -32
  138. package/dist/routes/post.js.map +1 -1
  139. package/dist/storage/index.d.ts +4 -0
  140. package/dist/types/storage.d.ts +49 -0
  141. package/dist/utils/colors.d.ts +44 -0
  142. package/dist/utils/helpers.d.ts +55 -0
  143. package/dist/utils/response.d.ts +9 -0
  144. package/dist/utils/response.js +2 -4
  145. package/dist/utils/response.js.map +1 -1
  146. package/package.json +17 -16
  147. package/robots.txt +74 -0
  148. package/src/favicon.ico +0 -0
@@ -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,28 @@ 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);
184
+ }
185
+ });
186
+ // Convert a number between bases
187
+ router.get('/:version/base', (req, res) => {
188
+ const { value, from, to } = req.query;
189
+ const { version } = req.params;
190
+ const baseFn = req.module.base;
191
+ if (!baseFn) {
192
+ error(res, 404, `Endpoint not available in ${version}.`);
193
+ return;
194
+ }
195
+ if (!value || typeof value !== 'string') {
196
+ error(res, 400, 'Please provide a value (?value={value})');
197
+ return;
198
+ }
199
+ try {
200
+ const result = baseFn(value, from !== undefined ? Number(from) : undefined, to !== undefined ? Number(to) : undefined);
201
+ res.jsonResponse(result);
202
+ }
203
+ catch (err) {
204
+ error(res, 400, err.message);
185
205
  }
186
206
  });
187
207
  // Generate captcha
@@ -204,7 +224,7 @@ router.get('/:version/captcha', (req, res) => {
204
224
  else {
205
225
  const text = req.query.text;
206
226
  if (!text) {
207
- error(res, 400, 'Please provide a valid argument (?text={text})', `${req.version}/captcha`);
227
+ error(res, 400, 'Please provide a valid argument (?text={text})');
208
228
  return;
209
229
  }
210
230
  const result = req.module.captcha(text);
@@ -212,7 +232,7 @@ router.get('/:version/captcha', (req, res) => {
212
232
  }
213
233
  }
214
234
  catch (err) {
215
- error(res, 400, err.message, `${req.version}/captcha`);
235
+ error(res, 400, err.message);
216
236
  }
217
237
  });
218
238
  // GET chart error
@@ -247,22 +267,22 @@ router.get('/:version/color', (req, res) => {
247
267
  }
248
268
  }
249
269
  catch (err) {
250
- error(res, 400, err.message, `${req.version}/color`);
270
+ error(res, 400, err.message);
251
271
  }
252
272
  });
253
273
  // Convert units
254
274
  router.get('/:version/convert', (req, res) => {
255
275
  const { value, from, to } = req.query;
256
276
  if (!value || isNaN(Number(value))) {
257
- error(res, 400, 'Please provide a valid value (?value={value})', `${req.version}/convert`);
277
+ error(res, 400, 'Please provide a valid value (?value={value})');
258
278
  return;
259
279
  }
260
280
  if (!from) {
261
- error(res, 400, 'Please provide a valid source unit (&from={unit})', `${req.version}/convert`);
281
+ error(res, 400, 'Please provide a valid source unit (&from={unit})');
262
282
  return;
263
283
  }
264
284
  if (!to) {
265
- error(res, 400, 'Please provide a valid target unit (&to={unit})', `${req.version}/convert`);
285
+ error(res, 400, 'Please provide a valid target unit (&to={unit})');
266
286
  return;
267
287
  }
268
288
  try {
@@ -277,7 +297,7 @@ router.get('/:version/convert', (req, res) => {
277
297
  }
278
298
  }
279
299
  catch (err) {
280
- error(res, 400, err.message, `${req.version}/convert`);
300
+ error(res, 400, err.message);
281
301
  }
282
302
  });
283
303
  // Generate fictitious credit card numbers
@@ -285,7 +305,7 @@ router.get('/:version/credit', (req, res) => {
285
305
  const creditFn = req.module
286
306
  .credit;
287
307
  if (!creditFn) {
288
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/credit`);
308
+ error(res, 404, `Endpoint not available in ${req.version}.`);
289
309
  return;
290
310
  }
291
311
  const { brand, count, format } = req.query;
@@ -294,7 +314,7 @@ router.get('/:version/credit', (req, res) => {
294
314
  res.jsonResponse(result);
295
315
  }
296
316
  catch (err) {
297
- error(res, 400, err.message, `${req.version}/credit`);
317
+ error(res, 400, err.message);
298
318
  }
299
319
  });
300
320
  // Parse a cron expression and compute next execution dates
@@ -303,16 +323,16 @@ router.get('/:version/cron', (req, res) => {
303
323
  const { version } = req.params;
304
324
  const cronFn = req.module.cron;
305
325
  if (!cronFn) {
306
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/cron`);
326
+ error(res, 404, `Endpoint not available in ${version}.`);
307
327
  return;
308
328
  }
309
329
  if (!expr) {
310
- error(res, 400, 'Please provide a cron expression (?expr=* * * * *)', `${version}/cron`);
330
+ error(res, 400, 'Please provide a cron expression (?expr=* * * * *)');
311
331
  return;
312
332
  }
313
333
  const parsedCount = count !== undefined ? parseInt(count, 10) : 5;
314
334
  if (isNaN(parsedCount)) {
315
- error(res, 400, 'Please provide a valid count (&count={n})', `${version}/cron`);
335
+ error(res, 400, 'Please provide a valid count (&count={n})');
316
336
  return;
317
337
  }
318
338
  try {
@@ -320,7 +340,7 @@ router.get('/:version/cron', (req, res) => {
320
340
  res.jsonResponse(result);
321
341
  }
322
342
  catch (err) {
323
- error(res, 400, err.message, `${req.version}/cron`);
343
+ error(res, 400, err.message);
324
344
  }
325
345
  });
326
346
  // RPG Dice roller
@@ -329,11 +349,11 @@ router.get('/:version/dice', (req, res) => {
329
349
  const { version } = req.params;
330
350
  const dice = req.module.dice;
331
351
  if (!dice) {
332
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/dice`);
352
+ error(res, 404, `Endpoint not available in ${version}.`);
333
353
  return;
334
354
  }
335
355
  if (!roll) {
336
- error(res, 400, 'Please provide a roll notation (?roll=2d6+3)', `${version}/dice`);
356
+ error(res, 400, 'Please provide a roll notation (?roll=2d6+3)');
337
357
  return;
338
358
  }
339
359
  try {
@@ -341,9 +361,11 @@ router.get('/:version/dice', (req, res) => {
341
361
  res.jsonResponse(result);
342
362
  }
343
363
  catch (err) {
344
- error(res, 400, err.message, `${req.version}/dice`);
364
+ error(res, 400, err.message);
345
365
  }
346
366
  });
367
+ // GET diff error
368
+ router.get('/:version/diff', postOnly('diff'));
347
369
  // Generate domain informations
348
370
  router.get('/:version/domain', (req, res) => {
349
371
  try {
@@ -351,7 +373,7 @@ router.get('/:version/domain', (req, res) => {
351
373
  res.jsonResponse(result);
352
374
  }
353
375
  catch (err) {
354
- error(res, 400, err.message, `${req.version}/domain`);
376
+ error(res, 400, err.message);
355
377
  }
356
378
  });
357
379
  // Encode / decode text
@@ -360,11 +382,11 @@ router.get('/:version/encode', (req, res) => {
360
382
  const { version } = req.params;
361
383
  const encode = req.module.encode;
362
384
  if (!encode) {
363
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/encode`);
385
+ error(res, 404, `Endpoint not available in ${version}.`);
364
386
  return;
365
387
  }
366
388
  if (!method || !Object.hasOwn(encode, method)) {
367
- error(res, 400, 'Please provide a valid method (?method={method})', `${version}/encode`);
389
+ error(res, 400, 'Please provide a valid method (?method={method})');
368
390
  return;
369
391
  }
370
392
  try {
@@ -372,7 +394,7 @@ router.get('/:version/encode', (req, res) => {
372
394
  res.jsonResponse({ method, result });
373
395
  }
374
396
  catch (err) {
375
- error(res, 400, err.message, `${req.version}/encode`);
397
+ error(res, 400, err.message);
376
398
  }
377
399
  });
378
400
  // Evaluate a math expression
@@ -381,11 +403,11 @@ router.get('/:version/evaluate', (req, res) => {
381
403
  const { version } = req.params;
382
404
  const evaluateFn = req.module.evaluate;
383
405
  if (!evaluateFn) {
384
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/evaluate`);
406
+ error(res, 404, `Endpoint not available in ${version}.`);
385
407
  return;
386
408
  }
387
409
  if (!expr || typeof expr !== 'string') {
388
- error(res, 400, 'Please provide a math expression (?expr={expression})', `${version}/evaluate`);
410
+ error(res, 400, 'Please provide a math expression (?expr={expression})');
389
411
  return;
390
412
  }
391
413
  try {
@@ -393,7 +415,7 @@ router.get('/:version/evaluate', (req, res) => {
393
415
  res.jsonResponse(result);
394
416
  }
395
417
  catch (err) {
396
- error(res, 400, err.message, `${req.version}/evaluate`);
418
+ error(res, 400, err.message);
397
419
  }
398
420
  });
399
421
  // Geographic distance and bearing between two coordinates
@@ -402,11 +424,11 @@ router.get('/:version/geo', (req, res) => {
402
424
  const { version } = req.params;
403
425
  const geo = req.module.geo;
404
426
  if (!geo) {
405
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/geo`);
427
+ error(res, 404, `Endpoint not available in ${version}.`);
406
428
  return;
407
429
  }
408
430
  if (lat1 === undefined || lon1 === undefined || lat2 === undefined || lon2 === undefined) {
409
- error(res, 400, 'Please provide lat1, lon1, lat2 and lon2', `${version}/geo`);
431
+ error(res, 400, 'Please provide lat1, lon1, lat2 and lon2');
410
432
  return;
411
433
  }
412
434
  try {
@@ -414,7 +436,7 @@ router.get('/:version/geo', (req, res) => {
414
436
  res.jsonResponse(result);
415
437
  }
416
438
  catch (err) {
417
- error(res, 400, err.message, `${req.version}/geo`);
439
+ error(res, 400, err.message);
418
440
  }
419
441
  });
420
442
  // GET hash error
@@ -449,9 +471,9 @@ router.get('/:version/infos', (req, res) => {
449
471
  res.jsonResponse({
450
472
  endpoints: new Set(paths).size,
451
473
  last_version: Object.keys(versions).pop(),
452
- documentation: DOCS_URL,
453
- github: 'https://github.com/20syldev/api',
454
- creation: 'November 25th 2024',
474
+ ...(env.DOCS_URL ? { documentation: env.DOCS_URL } : {}),
475
+ ...(env.REPO_URL ? { github: env.REPO_URL } : {}),
476
+ ...(env.INSTANCE_CREATED ? { creation: env.INSTANCE_CREATED } : {}),
455
477
  });
456
478
  });
457
479
  // Analyze an IP address
@@ -459,7 +481,7 @@ router.get('/:version/ip', (req, res) => {
459
481
  const address = req.query.address ?? req.ip ?? '';
460
482
  const ipFn = req.module.ip;
461
483
  if (!ipFn) {
462
- error(res, 404, `Endpoint not available in ${req.version}.`, `${req.latest}/ip`);
484
+ error(res, 404, `Endpoint not available in ${req.version}.`);
463
485
  return;
464
486
  }
465
487
  try {
@@ -467,7 +489,7 @@ router.get('/:version/ip', (req, res) => {
467
489
  res.jsonResponse(result);
468
490
  }
469
491
  catch (err) {
470
- error(res, 400, err.message, `${req.version}/ip`);
492
+ error(res, 400, err.message);
471
493
  }
472
494
  });
473
495
  // GET jwt error
@@ -476,11 +498,11 @@ router.get('/:version/jwt', postOnly('jwt'));
476
498
  router.get('/:version/levenshtein', (req, res) => {
477
499
  const { str1, str2 } = req.query;
478
500
  if (!str1 || typeof str1 !== 'string') {
479
- error(res, 400, 'Please provide a first string (?str1={string})', `${req.version}/levenshtein`);
501
+ error(res, 400, 'Please provide a first string (?str1={string})');
480
502
  return;
481
503
  }
482
504
  if (!str2 || typeof str2 !== 'string') {
483
- error(res, 400, 'Please provide a second string (&str2={string})', `${req.version}/levenshtein`);
505
+ error(res, 400, 'Please provide a second string (&str2={string})');
484
506
  return;
485
507
  }
486
508
  try {
@@ -488,7 +510,7 @@ router.get('/:version/levenshtein', (req, res) => {
488
510
  res.jsonResponse(result);
489
511
  }
490
512
  catch (err) {
491
- error(res, 400, err.message, `${req.version}/levenshtein`);
513
+ error(res, 400, err.message);
492
514
  }
493
515
  });
494
516
  // GET matrix error
@@ -501,15 +523,15 @@ router.get('/:version/palette', (req, res) => {
501
523
  const { version } = req.params;
502
524
  const palette = req.module.palette;
503
525
  if (!palette) {
504
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/palette`);
526
+ error(res, 404, `Endpoint not available in ${version}.`);
505
527
  return;
506
528
  }
507
529
  if (!color) {
508
- error(res, 400, 'Please provide a base color (?color=#ff6600)', `${version}/palette`);
530
+ error(res, 400, 'Please provide a base color (?color=#ff6600)');
509
531
  return;
510
532
  }
511
533
  if (!type) {
512
- error(res, 400, 'Please provide a palette type (&type=complementary)', `${version}/palette`);
534
+ error(res, 400, 'Please provide a palette type (&type=complementary)');
513
535
  return;
514
536
  }
515
537
  try {
@@ -517,7 +539,7 @@ router.get('/:version/palette', (req, res) => {
517
539
  res.jsonResponse(result);
518
540
  }
519
541
  catch (err) {
520
- error(res, 400, err.message, `${req.version}/palette`);
542
+ error(res, 400, err.message);
521
543
  }
522
544
  });
523
545
  // Generate a password or passphrase
@@ -526,7 +548,7 @@ router.get('/:version/password', (req, res) => {
526
548
  const { version } = req.params;
527
549
  const passwordFn = req.module.password;
528
550
  if (!passwordFn) {
529
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/password`);
551
+ error(res, 404, `Endpoint not available in ${version}.`);
530
552
  return;
531
553
  }
532
554
  const parseBool = (v, def) => (v === undefined ? def : v !== 'false');
@@ -543,7 +565,7 @@ router.get('/:version/password', (req, res) => {
543
565
  res.jsonResponse(result);
544
566
  }
545
567
  catch (err) {
546
- error(res, 400, err.message, `${req.version}/password`);
568
+ error(res, 400, err.message);
547
569
  }
548
570
  });
549
571
  // Generate personal data
@@ -553,7 +575,7 @@ router.get('/:version/personal', (req, res) => {
553
575
  res.jsonResponse(result);
554
576
  }
555
577
  catch (err) {
556
- error(res, 400, err.message, `${req.version}/personal`);
578
+ error(res, 400, err.message);
557
579
  }
558
580
  });
559
581
  // Generate a placeholder image or skeleton
@@ -562,7 +584,7 @@ router.get('/:version/placeholder', (req, res) => {
562
584
  const { version } = req.params;
563
585
  const placeholder = req.module.placeholder;
564
586
  if (!placeholder) {
565
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/placeholder`);
587
+ error(res, 404, `Endpoint not available in ${version}.`);
566
588
  return;
567
589
  }
568
590
  try {
@@ -570,14 +592,14 @@ router.get('/:version/placeholder', (req, res) => {
570
592
  res.type(result.contentType).send(result.body);
571
593
  }
572
594
  catch (err) {
573
- error(res, 400, err.message, `${req.version}/placeholder`);
595
+ error(res, 400, err.message);
574
596
  }
575
597
  });
576
598
  // Generate QR Code
577
599
  router.get('/:version/qrcode', async (req, res) => {
578
600
  const { url } = req.query;
579
601
  if (!url) {
580
- error(res, 400, 'Please provide a valid url (?url={URL})', `${req.version}/qrcode`);
602
+ error(res, 400, 'Please provide a valid url (?url={URL})');
581
603
  return;
582
604
  }
583
605
  try {
@@ -609,24 +631,26 @@ router.get('/:version/qrcode', async (req, res) => {
609
631
  }
610
632
  }
611
633
  catch (err) {
612
- error(res, 400, err.message, `${req.version}/qrcode`);
634
+ error(res, 400, err.message);
613
635
  }
614
636
  });
637
+ // GET read error
638
+ router.get('/:version/read', postOnly('read'));
615
639
  // Test a regex pattern against a text
616
640
  router.get('/:version/regex', (req, res) => {
617
641
  const { pattern, text, flags } = req.query;
618
642
  const { version } = req.params;
619
643
  const regexFn = req.module.regex;
620
644
  if (!regexFn) {
621
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/regex`);
645
+ error(res, 404, `Endpoint not available in ${version}.`);
622
646
  return;
623
647
  }
624
648
  if (!pattern) {
625
- error(res, 400, 'Please provide a pattern (?pattern={regex})', `${version}/regex`);
649
+ error(res, 400, 'Please provide a pattern (?pattern={regex})');
626
650
  return;
627
651
  }
628
652
  if (!text) {
629
- error(res, 400, 'Please provide a text (&text={string})', `${version}/regex`);
653
+ error(res, 400, 'Please provide a text (&text={string})');
630
654
  return;
631
655
  }
632
656
  try {
@@ -634,7 +658,29 @@ router.get('/:version/regex', (req, res) => {
634
658
  res.jsonResponse(result);
635
659
  }
636
660
  catch (err) {
637
- error(res, 400, err.message, `${req.version}/regex`);
661
+ error(res, 400, err.message);
662
+ }
663
+ });
664
+ // Parse, bump or compare semantic versions
665
+ router.get('/:version/semver', (req, res) => {
666
+ const { version: input, action, part, other } = req.query;
667
+ const { version } = req.params;
668
+ const semverFn = req.module.semver;
669
+ if (!semverFn) {
670
+ error(res, 404, `Endpoint not available in ${version}.`);
671
+ return;
672
+ }
673
+ if (!input || typeof input !== 'string') {
674
+ error(res, 400, 'Please provide a version (?version={version})');
675
+ return;
676
+ }
677
+ const restorePlus = (v) => v.replace(/ /g, '+');
678
+ try {
679
+ const result = semverFn(restorePlus(input), action, part, typeof other === 'string' ? restorePlus(other) : undefined);
680
+ res.jsonResponse(result);
681
+ }
682
+ catch (err) {
683
+ error(res, 400, err.message);
638
684
  }
639
685
  });
640
686
  // Statistics on a list of numbers
@@ -643,11 +689,11 @@ router.get('/:version/statistics', (req, res) => {
643
689
  const { version } = req.params;
644
690
  const statistics = req.module.statistics;
645
691
  if (!statistics) {
646
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/statistics`);
692
+ error(res, 404, `Endpoint not available in ${version}.`);
647
693
  return;
648
694
  }
649
695
  if (!values) {
650
- error(res, 400, 'Please provide a list of values (?values=1,2,3)', `${version}/statistics`);
696
+ error(res, 400, 'Please provide a list of values (?values=1,2,3)');
651
697
  return;
652
698
  }
653
699
  try {
@@ -655,7 +701,7 @@ router.get('/:version/statistics', (req, res) => {
655
701
  res.jsonResponse(result);
656
702
  }
657
703
  catch (err) {
658
- error(res, 400, err.message, `${req.version}/statistics`);
704
+ error(res, 400, err.message);
659
705
  }
660
706
  });
661
707
  // GET symmetric error
@@ -666,11 +712,11 @@ router.get('/:version/text', (req, res) => {
666
712
  const { version } = req.params;
667
713
  const textMod = req.module.text;
668
714
  if (!textMod) {
669
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/text`);
715
+ error(res, 404, `Endpoint not available in ${version}.`);
670
716
  return;
671
717
  }
672
718
  if (!method || !Object.hasOwn(textMod, method)) {
673
- error(res, 400, 'Please provide a valid method (?method={slug|stats|lorem|number})', `${version}/text`);
719
+ error(res, 400, 'Please provide a valid method (?method={slug|stats|lorem|number})');
674
720
  return;
675
721
  }
676
722
  try {
@@ -692,7 +738,7 @@ router.get('/:version/text', (req, res) => {
692
738
  res.jsonResponse({ method, result });
693
739
  }
694
740
  catch (err) {
695
- error(res, 400, err.message, `${req.version}/text`);
741
+ error(res, 400, err.message);
696
742
  }
697
743
  });
698
744
  // GET tic-tac-toe errors
@@ -708,7 +754,7 @@ router.get('/:version/time', (req, res) => {
708
754
  res.jsonResponse(time);
709
755
  }
710
756
  catch (err) {
711
- error(res, 400, err.message, `${req.version}/time`);
757
+ error(res, 400, err.message);
712
758
  }
713
759
  });
714
760
  // GET csv error
@@ -721,11 +767,11 @@ router.get('/:version/url', (req, res) => {
721
767
  const { version } = req.params;
722
768
  const parseUrlFn = req.module.parseUrl;
723
769
  if (!parseUrlFn) {
724
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/url`);
770
+ error(res, 404, `Endpoint not available in ${version}.`);
725
771
  return;
726
772
  }
727
773
  if (!url || typeof url !== 'string') {
728
- error(res, 400, 'Please provide a URL (?url={URL})', `${version}/url`);
774
+ error(res, 400, 'Please provide a URL (?url={URL})');
729
775
  return;
730
776
  }
731
777
  try {
@@ -733,7 +779,28 @@ router.get('/:version/url', (req, res) => {
733
779
  res.jsonResponse(result);
734
780
  }
735
781
  catch (err) {
736
- error(res, 400, err.message, `${req.version}/url`);
782
+ error(res, 400, err.message);
783
+ }
784
+ });
785
+ // Generate or parse a UUID
786
+ router.get('/:version/uuid', (req, res) => {
787
+ const { uuid: input, count } = req.query;
788
+ const { version } = req.params;
789
+ const uuidFn = req.module.uuid;
790
+ if (!uuidFn) {
791
+ error(res, 404, `Endpoint not available in ${version}.`);
792
+ return;
793
+ }
794
+ if (input !== undefined && typeof input !== 'string') {
795
+ error(res, 400, 'Please provide a valid UUID (?uuid={uuid})');
796
+ return;
797
+ }
798
+ try {
799
+ const result = uuidFn(input, count !== undefined ? Number(count) : undefined);
800
+ res.jsonResponse(result);
801
+ }
802
+ catch (err) {
803
+ error(res, 400, err.message);
737
804
  }
738
805
  });
739
806
  // Generate username
@@ -743,7 +810,7 @@ router.get('/:version/username', (req, res) => {
743
810
  res.jsonResponse(result);
744
811
  }
745
812
  catch (err) {
746
- error(res, 400, err.message, `${req.version}/username`);
813
+ error(res, 400, err.message);
747
814
  }
748
815
  });
749
816
  // Validate data (luhn, iban, email)
@@ -752,15 +819,15 @@ router.get('/:version/validate', (req, res) => {
752
819
  const { version } = req.params;
753
820
  const validate = req.module.validate;
754
821
  if (!validate) {
755
- error(res, 404, `Endpoint not available in ${version}.`, `${req.latest}/validate`);
822
+ error(res, 404, `Endpoint not available in ${version}.`);
756
823
  return;
757
824
  }
758
825
  if (!type || !Object.hasOwn(validate, type)) {
759
- error(res, 400, 'Please provide a valid type (?type={luhn|iban|email})', `${version}/validate`);
826
+ error(res, 400, 'Please provide a valid type (?type={luhn|iban|email})');
760
827
  return;
761
828
  }
762
829
  if (!value) {
763
- error(res, 400, 'Please provide a value (&value={value})', `${version}/validate`);
830
+ error(res, 400, 'Please provide a value (&value={value})');
764
831
  return;
765
832
  }
766
833
  try {
@@ -768,7 +835,7 @@ router.get('/:version/validate', (req, res) => {
768
835
  res.jsonResponse(result);
769
836
  }
770
837
  catch (err) {
771
- error(res, 400, err.message, `${req.version}/validate`);
838
+ error(res, 400, err.message);
772
839
  }
773
840
  });
774
841
  export default router;