@20syldev/api 4.7.0 → 4.9.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.
- package/README.md +84 -47
- package/dist/app.js +6 -6
- package/dist/app.js.map +1 -1
- package/dist/config/env.js.map +1 -1
- package/dist/config/versions.js +22 -3
- package/dist/config/versions.js.map +1 -1
- package/dist/constants.js +27 -12
- package/dist/constants.js.map +1 -1
- package/dist/middleware/error.js +2 -2
- package/dist/middleware/error.js.map +1 -1
- package/dist/middleware/logger.js.map +1 -1
- package/dist/middleware/ratelimit.js +2 -2
- package/dist/middleware/ratelimit.js.map +1 -1
- package/dist/middleware/version.js.map +1 -1
- package/dist/modules/v3.js +1 -1
- package/dist/modules/v3.js.map +1 -1
- package/{src/modules/v4/address.ts → dist/modules/v4/address.js} +14 -46
- package/dist/modules/v4/address.js.map +1 -0
- package/{src/modules/v4/agent.ts → dist/modules/v4/agent.js} +26 -38
- package/dist/modules/v4/agent.js.map +1 -0
- package/dist/modules/v4/algorithms.js +79 -0
- package/dist/modules/v4/algorithms.js.map +1 -1
- package/dist/modules/v4/avatar.js +136 -0
- package/dist/modules/v4/avatar.js.map +1 -0
- package/dist/modules/v4/barcode.js +440 -0
- package/dist/modules/v4/barcode.js.map +1 -0
- package/dist/modules/v4/captcha.js +7 -0
- package/dist/modules/v4/captcha.js.map +1 -1
- package/dist/modules/v4/chat.js +9 -1
- package/dist/modules/v4/chat.js.map +1 -1
- package/dist/modules/v4/color.js +8 -1
- package/dist/modules/v4/color.js.map +1 -1
- package/dist/modules/v4/convert.js +9 -0
- package/dist/modules/v4/convert.js.map +1 -1
- package/dist/modules/v4/credit.js +104 -0
- package/dist/modules/v4/credit.js.map +1 -0
- package/dist/modules/v4/cron.js +202 -0
- package/dist/modules/v4/cron.js.map +1 -0
- package/dist/modules/v4/dice.js +7 -0
- package/dist/modules/v4/dice.js.map +1 -1
- package/dist/modules/v4/domain.js +6 -1
- package/dist/modules/v4/domain.js.map +1 -1
- package/dist/modules/v4/encode.js +71 -0
- package/dist/modules/v4/encode.js.map +1 -1
- package/dist/modules/v4/geo.js +11 -1
- package/dist/modules/v4/geo.js.map +1 -1
- package/dist/modules/v4/hash.js +10 -1
- package/dist/modules/v4/hash.js.map +1 -1
- package/dist/modules/v4/hyperplanning.js +9 -1
- package/dist/modules/v4/hyperplanning.js.map +1 -1
- package/{src/modules/v4/ip.ts → dist/modules/v4/ip.js} +58 -60
- package/dist/modules/v4/ip.js.map +1 -0
- package/dist/modules/v4/levenshtein.js +8 -0
- package/dist/modules/v4/levenshtein.js.map +1 -1
- package/dist/modules/v4/palette.js +9 -1
- package/dist/modules/v4/palette.js.map +1 -1
- package/{src/modules/v4/password.ts → dist/modules/v4/password.js} +25 -63
- package/dist/modules/v4/password.js.map +1 -0
- package/dist/modules/v4/personal.js +14 -18
- package/dist/modules/v4/personal.js.map +1 -1
- package/dist/modules/v4/placeholder.js +8 -0
- package/dist/modules/v4/placeholder.js.map +1 -1
- package/dist/modules/v4/qrcode.js +10 -3
- package/dist/modules/v4/qrcode.js.map +1 -1
- package/dist/modules/v4/regex.js +48 -0
- package/dist/modules/v4/regex.js.map +1 -0
- package/dist/modules/v4/statistics.js +7 -0
- package/dist/modules/v4/statistics.js.map +1 -1
- package/dist/modules/v4/text.js +30 -0
- package/dist/modules/v4/text.js.map +1 -1
- package/dist/modules/v4/tic_tac_toe.js +9 -1
- package/dist/modules/v4/tic_tac_toe.js.map +1 -1
- package/dist/modules/v4/time.js +62 -11
- package/dist/modules/v4/time.js.map +1 -1
- package/dist/modules/v4/token.js +17 -8
- package/dist/modules/v4/token.js.map +1 -1
- package/dist/modules/v4/username.js +5 -0
- package/dist/modules/v4/username.js.map +1 -1
- package/dist/modules/v4/validate.js +21 -0
- package/dist/modules/v4/validate.js.map +1 -1
- package/dist/modules/v4.js +10 -1
- package/dist/modules/v4.js.map +1 -1
- package/dist/routes/delete.js.map +1 -1
- package/dist/routes/get.js +208 -48
- package/dist/routes/get.js.map +1 -1
- package/dist/routes/index.js +2 -2
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/patch.js.map +1 -1
- package/dist/routes/post.js +2 -2
- package/dist/routes/post.js.map +1 -1
- package/dist/utils/response.js.map +1 -1
- package/package.json +2 -1
- package/.github/FUNDING.yml +0 -1
- package/.prettierrc +0 -7
- package/eslint.config.js +0 -24
- package/robots.txt +0 -74
- package/src/app.ts +0 -53
- package/src/config/env.ts +0 -87
- package/src/config/plans.ts +0 -61
- package/src/config/versions.ts +0 -119
- package/src/constants.ts +0 -46
- package/src/favicon.ico +0 -0
- package/src/middleware/cors.ts +0 -23
- package/src/middleware/error.ts +0 -16
- package/src/middleware/json.ts +0 -9
- package/src/middleware/logger.ts +0 -32
- package/src/middleware/ratelimit.ts +0 -89
- package/src/middleware/version.ts +0 -40
- package/src/modules/v3/algorithms.js +0 -218
- package/src/modules/v3/captcha.js +0 -60
- package/src/modules/v3/chat.js +0 -111
- package/src/modules/v3/color.js +0 -60
- package/src/modules/v3/convert.js +0 -39
- package/src/modules/v3/domain.js +0 -86
- package/src/modules/v3/hash.js +0 -16
- package/src/modules/v3/hyperplanning.js +0 -56
- package/src/modules/v3/levenshtein.js +0 -46
- package/src/modules/v3/personal.js +0 -139
- package/src/modules/v3/qrcode.js +0 -20
- package/src/modules/v3/tic_tac_toe.js +0 -242
- package/src/modules/v3/time.js +0 -98
- package/src/modules/v3/token.js +0 -54
- package/src/modules/v3/username.js +0 -94
- package/src/modules/v3/utils.js +0 -77
- package/src/modules/v3.js +0 -15
- package/src/modules/v4/algorithms.ts +0 -276
- package/src/modules/v4/captcha.ts +0 -114
- package/src/modules/v4/chat.ts +0 -130
- package/src/modules/v4/color.ts +0 -75
- package/src/modules/v4/convert.ts +0 -127
- package/src/modules/v4/dice.ts +0 -46
- package/src/modules/v4/domain.ts +0 -86
- package/src/modules/v4/encode.ts +0 -241
- package/src/modules/v4/geo.ts +0 -63
- package/src/modules/v4/hash.ts +0 -32
- package/src/modules/v4/hyperplanning.ts +0 -93
- package/src/modules/v4/levenshtein.ts +0 -46
- package/src/modules/v4/palette.ts +0 -71
- package/src/modules/v4/personal.ts +0 -140
- package/src/modules/v4/placeholder.ts +0 -197
- package/src/modules/v4/qrcode.ts +0 -121
- package/src/modules/v4/statistics.ts +0 -62
- package/src/modules/v4/text.ts +0 -330
- package/src/modules/v4/tic_tac_toe.ts +0 -264
- package/src/modules/v4/time.ts +0 -103
- package/src/modules/v4/token.ts +0 -53
- package/src/modules/v4/username.ts +0 -94
- package/src/modules/v4/validate.ts +0 -76
- package/src/modules/v4.ts +0 -27
- package/src/routes/delete.ts +0 -72
- package/src/routes/get.ts +0 -835
- package/src/routes/index.ts +0 -59
- package/src/routes/patch.ts +0 -45
- package/src/routes/post.ts +0 -209
- package/src/storage/index.ts +0 -16
- package/src/types/express.d.ts +0 -17
- package/src/types/storage.ts +0 -48
- package/src/utils/colors.ts +0 -91
- package/src/utils/helpers.ts +0 -90
- package/src/utils/response.ts +0 -28
- package/tests/integration/api.test.ts +0 -716
- package/tests/tsconfig.json +0 -3
- package/tests/unit/address.test.ts +0 -84
- package/tests/unit/agent.test.ts +0 -113
- package/tests/unit/algorithms.test.ts +0 -121
- package/tests/unit/captcha.test.ts +0 -62
- package/tests/unit/chat.test.ts +0 -54
- package/tests/unit/color.test.ts +0 -54
- package/tests/unit/convert.test.ts +0 -68
- package/tests/unit/dice.test.ts +0 -58
- package/tests/unit/domain.test.ts +0 -48
- package/tests/unit/encode.test.ts +0 -109
- package/tests/unit/geo.test.ts +0 -46
- package/tests/unit/hash.test.ts +0 -45
- package/tests/unit/hyperplanning.test.ts +0 -97
- package/tests/unit/ip.test.ts +0 -140
- package/tests/unit/levenshtein.test.ts +0 -35
- package/tests/unit/palette.test.ts +0 -54
- package/tests/unit/password.test.ts +0 -86
- package/tests/unit/personal.test.ts +0 -66
- package/tests/unit/placeholder.test.ts +0 -58
- package/tests/unit/qrcode.test.ts +0 -83
- package/tests/unit/statistics.test.ts +0 -58
- package/tests/unit/text.test.ts +0 -108
- package/tests/unit/tic_tac_toe.test.ts +0 -56
- package/tests/unit/time.test.ts +0 -68
- package/tests/unit/token.test.ts +0 -62
- package/tests/unit/username.test.ts +0 -35
- package/tests/unit/validate.test.ts +0 -72
- package/tsconfig.json +0 -17
- package/tsconfig.test.json +0 -9
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
type ConversionFn = (val: number) => number;
|
|
2
|
-
|
|
3
|
-
const TEMPERATURE_UNITS = new Set(['celsius', 'fahrenheit', 'kelvin']);
|
|
4
|
-
const ABSOLUTE_ZERO: Record<string, number> = { celsius: -273.15, fahrenheit: -459.67, kelvin: 0 };
|
|
5
|
-
|
|
6
|
-
const conversions: Record<string, Record<string, ConversionFn>> = {
|
|
7
|
-
// Temperature
|
|
8
|
-
celsius: {
|
|
9
|
-
fahrenheit: (v) => (v * 9) / 5 + 32,
|
|
10
|
-
kelvin: (v) => v + 273.15,
|
|
11
|
-
},
|
|
12
|
-
fahrenheit: {
|
|
13
|
-
celsius: (v) => ((v - 32) * 5) / 9,
|
|
14
|
-
kelvin: (v) => ((v - 32) * 5) / 9 + 273.15,
|
|
15
|
-
},
|
|
16
|
-
kelvin: {
|
|
17
|
-
celsius: (v) => v - 273.15,
|
|
18
|
-
fahrenheit: (v) => ((v - 273.15) * 9) / 5 + 32,
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
// Length
|
|
22
|
-
km: {
|
|
23
|
-
mi: (v) => v * 0.621371,
|
|
24
|
-
m: (v) => v * 1000,
|
|
25
|
-
ft: (v) => v * 3280.84,
|
|
26
|
-
cm: (v) => v * 100000,
|
|
27
|
-
in: (v) => v * 39370.1,
|
|
28
|
-
yd: (v) => v * 1093.61,
|
|
29
|
-
},
|
|
30
|
-
mi: {
|
|
31
|
-
km: (v) => v * 1.60934,
|
|
32
|
-
m: (v) => v * 1609.34,
|
|
33
|
-
ft: (v) => v * 5280,
|
|
34
|
-
cm: (v) => v * 160934,
|
|
35
|
-
in: (v) => v * 63360,
|
|
36
|
-
yd: (v) => v * 1760,
|
|
37
|
-
},
|
|
38
|
-
m: {
|
|
39
|
-
km: (v) => v / 1000,
|
|
40
|
-
mi: (v) => v * 0.000621371,
|
|
41
|
-
ft: (v) => v * 3.28084,
|
|
42
|
-
cm: (v) => v * 100,
|
|
43
|
-
in: (v) => v * 39.3701,
|
|
44
|
-
yd: (v) => v * 1.09361,
|
|
45
|
-
},
|
|
46
|
-
ft: {
|
|
47
|
-
km: (v) => v * 0.0003048,
|
|
48
|
-
mi: (v) => v / 5280,
|
|
49
|
-
m: (v) => v * 0.3048,
|
|
50
|
-
cm: (v) => v * 30.48,
|
|
51
|
-
in: (v) => v * 12,
|
|
52
|
-
yd: (v) => v / 3,
|
|
53
|
-
},
|
|
54
|
-
cm: {
|
|
55
|
-
km: (v) => v / 100000,
|
|
56
|
-
mi: (v) => v / 160934,
|
|
57
|
-
m: (v) => v / 100,
|
|
58
|
-
ft: (v) => v / 30.48,
|
|
59
|
-
in: (v) => v / 2.54,
|
|
60
|
-
yd: (v) => v / 91.44,
|
|
61
|
-
},
|
|
62
|
-
in: {
|
|
63
|
-
km: (v) => v / 39370.1,
|
|
64
|
-
mi: (v) => v / 63360,
|
|
65
|
-
m: (v) => v * 0.0254,
|
|
66
|
-
ft: (v) => v / 12,
|
|
67
|
-
cm: (v) => v * 2.54,
|
|
68
|
-
yd: (v) => v / 36,
|
|
69
|
-
},
|
|
70
|
-
yd: {
|
|
71
|
-
km: (v) => v * 0.0009144,
|
|
72
|
-
mi: (v) => v / 1760,
|
|
73
|
-
m: (v) => v * 0.9144,
|
|
74
|
-
ft: (v) => v * 3,
|
|
75
|
-
cm: (v) => v * 91.44,
|
|
76
|
-
in: (v) => v * 36,
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
// Weight
|
|
80
|
-
kg: { lb: (v) => v * 2.20462, oz: (v) => v * 35.274, g: (v) => v * 1000, ton: (v) => v / 1000 },
|
|
81
|
-
lb: { kg: (v) => v * 0.453592, oz: (v) => v * 16, g: (v) => v * 453.592, ton: (v) => v * 0.000453592 },
|
|
82
|
-
oz: { kg: (v) => v * 0.0283495, lb: (v) => v / 16, g: (v) => v * 28.3495, ton: (v) => v * 0.0000283495 },
|
|
83
|
-
g: { kg: (v) => v / 1000, lb: (v) => v * 0.00220462, oz: (v) => v * 0.035274, ton: (v) => v / 1000000 },
|
|
84
|
-
ton: { kg: (v) => v * 1000, lb: (v) => v * 2204.62, oz: (v) => v * 35274, g: (v) => v * 1000000 },
|
|
85
|
-
|
|
86
|
-
// Data
|
|
87
|
-
b: { kb: (v) => v / 1024, mb: (v) => v / 1048576, gb: (v) => v / 1073741824, tb: (v) => v / 1099511627776 },
|
|
88
|
-
kb: { b: (v) => v * 1024, mb: (v) => v / 1024, gb: (v) => v / 1048576, tb: (v) => v / 1073741824 },
|
|
89
|
-
mb: { b: (v) => v * 1048576, kb: (v) => v * 1024, gb: (v) => v / 1024, tb: (v) => v / 1048576 },
|
|
90
|
-
gb: { b: (v) => v * 1073741824, kb: (v) => v * 1048576, mb: (v) => v * 1024, tb: (v) => v / 1024 },
|
|
91
|
-
tb: { b: (v) => v * 1099511627776, kb: (v) => v * 1073741824, mb: (v) => v * 1048576, gb: (v) => v * 1024 },
|
|
92
|
-
|
|
93
|
-
// Speed
|
|
94
|
-
'km/h': { mph: (v) => v * 0.621371, 'm/s': (v) => v / 3.6, knots: (v) => v * 0.539957 },
|
|
95
|
-
mph: { 'km/h': (v) => v * 1.60934, 'm/s': (v) => v * 0.44704, knots: (v) => v * 0.868976 },
|
|
96
|
-
'm/s': { 'km/h': (v) => v * 3.6, mph: (v) => v * 2.23694, knots: (v) => v * 1.94384 },
|
|
97
|
-
knots: { 'km/h': (v) => v * 1.852, mph: (v) => v * 1.15078, 'm/s': (v) => v * 0.514444 },
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Converts a numeric value from one unit to another.
|
|
102
|
-
*
|
|
103
|
-
* @param value - The numeric value to convert
|
|
104
|
-
* @param from - The source unit (e.g. "km", "celsius", "kg")
|
|
105
|
-
* @param to - The target unit (e.g. "mi", "fahrenheit", "lb")
|
|
106
|
-
* @returns Object with source unit, target unit, original value, and converted result
|
|
107
|
-
* @throws Error if the conversion pair is unsupported, the value is NaN, or the temperature is below absolute zero
|
|
108
|
-
*/
|
|
109
|
-
export default function convert(
|
|
110
|
-
value: number,
|
|
111
|
-
from: string,
|
|
112
|
-
to: string,
|
|
113
|
-
): { from: string; to: string; value: number; result: number } {
|
|
114
|
-
const fromKey = from.toLowerCase();
|
|
115
|
-
const toKey = to.toLowerCase();
|
|
116
|
-
const convertFn = conversions[fromKey]?.[toKey];
|
|
117
|
-
|
|
118
|
-
if (!convertFn) throw new Error('Invalid conversion unit');
|
|
119
|
-
if (isNaN(value)) throw new Error('Value must be a number');
|
|
120
|
-
|
|
121
|
-
if (TEMPERATURE_UNITS.has(fromKey)) {
|
|
122
|
-
const minValue = ABSOLUTE_ZERO[fromKey]!;
|
|
123
|
-
if (value < minValue) throw new Error('Value must be greater than absolute zero');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return { from, to, value, result: convertFn(value) };
|
|
127
|
-
}
|
package/src/modules/v4/dice.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
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
|
-
/**
|
|
11
|
-
* Rolls dice using standard tabletop notation and returns individual results with a total.
|
|
12
|
-
*
|
|
13
|
-
* @param roll - Dice notation string (e.g. "2d6+3", "d20", "4d8-1")
|
|
14
|
-
* @returns Roll breakdown including count, sides, modifier, individual results, and total
|
|
15
|
-
* @throws Error if the notation is missing, invalid, or out of bounds
|
|
16
|
-
*/
|
|
17
|
-
export default function dice(roll: string): DiceResult {
|
|
18
|
-
if (!roll) throw new Error('A roll notation is required (e.g. 2d6+3)');
|
|
19
|
-
if (typeof roll !== 'string') throw new Error('Roll must be a string');
|
|
20
|
-
|
|
21
|
-
const match = /^(\d*)d(\d+)([+-]\d+)?$/i.exec(roll.trim().replace(/\s+/g, '+'));
|
|
22
|
-
if (!match) throw new Error('Invalid notation. Use NdX or NdX+M (e.g. 2d6+3)');
|
|
23
|
-
|
|
24
|
-
const count = match[1] ? parseInt(match[1], 10) : 1;
|
|
25
|
-
const sides = parseInt(match[2]!, 10);
|
|
26
|
-
const modifier = match[3] ? parseInt(match[3], 10) : 0;
|
|
27
|
-
|
|
28
|
-
if (count < 1 || count > 100) throw new Error('Number of dice must be between 1 and 100');
|
|
29
|
-
if (sides < 2 || sides > 1000) throw new Error('Number of sides must be between 2 and 1000');
|
|
30
|
-
|
|
31
|
-
const results: number[] = [];
|
|
32
|
-
for (let i = 0; i < count; i++) {
|
|
33
|
-
results.push(1 + Math.floor(Math.random() * sides));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const total = results.reduce((a, b) => a + b, 0) + modifier;
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
roll: `${count}d${sides}${modifier ? (modifier > 0 ? `+${modifier}` : modifier) : ''}`,
|
|
40
|
-
count,
|
|
41
|
-
sides,
|
|
42
|
-
modifier,
|
|
43
|
-
results,
|
|
44
|
-
total,
|
|
45
|
-
};
|
|
46
|
-
}
|
package/src/modules/v4/domain.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { genIP, random } from '../../utils/helpers.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates a randomized fictional domain profile with metadata.
|
|
5
|
-
*
|
|
6
|
-
* @returns Object containing domain name, IP addresses, DNS info, SEO score, and other domain attributes
|
|
7
|
-
*/
|
|
8
|
-
export default function domain(): Record<string, unknown> {
|
|
9
|
-
const subdomains = [
|
|
10
|
-
'fr.',
|
|
11
|
-
'en.',
|
|
12
|
-
'docs.',
|
|
13
|
-
'api.',
|
|
14
|
-
'projects.',
|
|
15
|
-
'app.',
|
|
16
|
-
'web.',
|
|
17
|
-
'info.',
|
|
18
|
-
'dev.',
|
|
19
|
-
'shop.',
|
|
20
|
-
'blog.',
|
|
21
|
-
'support.',
|
|
22
|
-
'mail.',
|
|
23
|
-
'forum.',
|
|
24
|
-
];
|
|
25
|
-
const domains = [
|
|
26
|
-
'example',
|
|
27
|
-
'site',
|
|
28
|
-
'test',
|
|
29
|
-
'demo',
|
|
30
|
-
'page',
|
|
31
|
-
'store',
|
|
32
|
-
'portfolio',
|
|
33
|
-
'platform',
|
|
34
|
-
'hub',
|
|
35
|
-
'network',
|
|
36
|
-
'service',
|
|
37
|
-
'cloud',
|
|
38
|
-
'solutions',
|
|
39
|
-
'company',
|
|
40
|
-
];
|
|
41
|
-
const tlds = [
|
|
42
|
-
'.com',
|
|
43
|
-
'.fr',
|
|
44
|
-
'.eu',
|
|
45
|
-
'.dev',
|
|
46
|
-
'.net',
|
|
47
|
-
'.org',
|
|
48
|
-
'.io',
|
|
49
|
-
'.tech',
|
|
50
|
-
'.biz',
|
|
51
|
-
'.info',
|
|
52
|
-
'.co',
|
|
53
|
-
'.app',
|
|
54
|
-
'.store',
|
|
55
|
-
'.online',
|
|
56
|
-
'.shop',
|
|
57
|
-
'.tv',
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
const domainName = `${random(domains)}${random(tlds)}`;
|
|
61
|
-
const fulldomain = `${random(subdomains)}${domainName}`;
|
|
62
|
-
|
|
63
|
-
const ips = Array.from({ length: Math.floor(Math.random() * 3) + 1 }, genIP);
|
|
64
|
-
const dns = Array.from({ length: Math.floor(Math.random() * 5) + 1 }, genIP);
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
domain: domainName,
|
|
68
|
-
full_domain: fulldomain,
|
|
69
|
-
ip_address: ips,
|
|
70
|
-
ssl_certified: Math.random() > 0.5,
|
|
71
|
-
hosting_provider: random(['AWS', 'Bluehost', 'DigitalOcean', 'GitHub', 'HostGator', 'Render', 'SiteGround']),
|
|
72
|
-
dns_servers: dns,
|
|
73
|
-
dns_provider: random(['AWS Route 53', 'Cloudflare', 'GoDaddy', 'Google DNS', 'Namecheap']),
|
|
74
|
-
traffic: `${Math.floor(Math.random() * 10000)} visits/day`,
|
|
75
|
-
seo_score: Math.floor(Math.random() * 100),
|
|
76
|
-
page_rank: Math.floor(Math.random() * 10),
|
|
77
|
-
country: random(['Australia', 'Canada', 'France', 'Germany', 'India', 'Japan', 'UK', 'USA']),
|
|
78
|
-
website_type: random(['Blog', 'Community', 'Corporate', 'Educational', 'E-commerce', 'Personal', 'Portfolio']),
|
|
79
|
-
random_name: domainName.split('.')[0],
|
|
80
|
-
random_subdomain: fulldomain.split('.')[0],
|
|
81
|
-
random_tld: domainName.split('.').pop(),
|
|
82
|
-
backlinks_count: Math.floor(Math.random() * 1000),
|
|
83
|
-
creation_date: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toISOString(),
|
|
84
|
-
expiration_date: new Date(Date.now() + Math.floor(Math.random() * 10000000000)).toISOString(),
|
|
85
|
-
};
|
|
86
|
-
}
|
package/src/modules/v4/encode.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { MAX_STRING_LENGTH } from '../../constants.js';
|
|
2
|
-
|
|
3
|
-
const MORSE_TABLE: Record<string, string> = {
|
|
4
|
-
A: '.-',
|
|
5
|
-
B: '-...',
|
|
6
|
-
C: '-.-.',
|
|
7
|
-
D: '-..',
|
|
8
|
-
E: '.',
|
|
9
|
-
F: '..-.',
|
|
10
|
-
G: '--.',
|
|
11
|
-
H: '....',
|
|
12
|
-
I: '..',
|
|
13
|
-
J: '.---',
|
|
14
|
-
K: '-.-',
|
|
15
|
-
L: '.-..',
|
|
16
|
-
M: '--',
|
|
17
|
-
N: '-.',
|
|
18
|
-
O: '---',
|
|
19
|
-
P: '.--.',
|
|
20
|
-
Q: '--.-',
|
|
21
|
-
R: '.-.',
|
|
22
|
-
S: '...',
|
|
23
|
-
T: '-',
|
|
24
|
-
U: '..-',
|
|
25
|
-
V: '...-',
|
|
26
|
-
W: '.--',
|
|
27
|
-
X: '-..-',
|
|
28
|
-
Y: '-.--',
|
|
29
|
-
Z: '--..',
|
|
30
|
-
'0': '-----',
|
|
31
|
-
'1': '.----',
|
|
32
|
-
'2': '..---',
|
|
33
|
-
'3': '...--',
|
|
34
|
-
'4': '....-',
|
|
35
|
-
'5': '.....',
|
|
36
|
-
'6': '-....',
|
|
37
|
-
'7': '--...',
|
|
38
|
-
'8': '---..',
|
|
39
|
-
'9': '----.',
|
|
40
|
-
'.': '.-.-.-',
|
|
41
|
-
',': '--..--',
|
|
42
|
-
'?': '..--..',
|
|
43
|
-
"'": '.----.',
|
|
44
|
-
'!': '-.-.--',
|
|
45
|
-
'/': '-..-.',
|
|
46
|
-
'(': '-.--.',
|
|
47
|
-
')': '-.--.-',
|
|
48
|
-
'&': '.-...',
|
|
49
|
-
':': '---...',
|
|
50
|
-
';': '-.-.-.',
|
|
51
|
-
'=': '-...-',
|
|
52
|
-
'+': '.-.-.',
|
|
53
|
-
'-': '-....-',
|
|
54
|
-
_: '..--.-',
|
|
55
|
-
'"': '.-..-.',
|
|
56
|
-
$: '...-..-',
|
|
57
|
-
'@': '.--.-.',
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const MORSE_REVERSE: Record<string, string> = Object.fromEntries(Object.entries(MORSE_TABLE).map(([k, v]) => [v, k]));
|
|
61
|
-
|
|
62
|
-
function checkText(value: string): void {
|
|
63
|
-
if (!value) throw new Error('A value is required');
|
|
64
|
-
if (typeof value !== 'string') throw new Error('Value must be a string');
|
|
65
|
-
if (value.length > MAX_STRING_LENGTH)
|
|
66
|
-
throw new Error(`Value must be less than ${MAX_STRING_LENGTH} characters long`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Encodes a UTF-8 string to Base64.
|
|
71
|
-
*
|
|
72
|
-
* @param value - The string to encode
|
|
73
|
-
* @returns Base64-encoded string
|
|
74
|
-
* @throws Error if value is missing, not a string, or too long
|
|
75
|
-
*/
|
|
76
|
-
export function base64encode(value: string): string {
|
|
77
|
-
checkText(value);
|
|
78
|
-
return Buffer.from(value, 'utf-8').toString('base64');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Decodes a Base64 string to UTF-8.
|
|
83
|
-
*
|
|
84
|
-
* @param value - The Base64 string to decode
|
|
85
|
-
* @returns Decoded UTF-8 string
|
|
86
|
-
* @throws Error if value is missing, not valid Base64, or too long
|
|
87
|
-
*/
|
|
88
|
-
export function base64decode(value: string): string {
|
|
89
|
-
checkText(value);
|
|
90
|
-
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value)) throw new Error('Invalid Base64 string');
|
|
91
|
-
return Buffer.from(value, 'base64').toString('utf-8');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Percent-encodes a string for safe use in a URL.
|
|
96
|
-
*
|
|
97
|
-
* @param value - The string to encode
|
|
98
|
-
* @returns URL-encoded string
|
|
99
|
-
* @throws Error if value is missing, not a string, or too long
|
|
100
|
-
*/
|
|
101
|
-
export function urlencode(value: string): string {
|
|
102
|
-
checkText(value);
|
|
103
|
-
return encodeURIComponent(value);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Decodes a percent-encoded URL string.
|
|
108
|
-
*
|
|
109
|
-
* @param value - The URL-encoded string to decode
|
|
110
|
-
* @returns Decoded string
|
|
111
|
-
* @throws Error if value is missing, not a valid URL-encoded string, or too long
|
|
112
|
-
*/
|
|
113
|
-
export function urldecode(value: string): string {
|
|
114
|
-
checkText(value);
|
|
115
|
-
try {
|
|
116
|
-
return decodeURIComponent(value);
|
|
117
|
-
} catch {
|
|
118
|
-
throw new Error('Invalid URL-encoded string');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Converts a plain text string to Morse code.
|
|
124
|
-
*
|
|
125
|
-
* @param value - The text to encode in Morse code
|
|
126
|
-
* @returns Morse code string where letters are separated by spaces and words by " / "
|
|
127
|
-
* @throws Error if value contains unsupported characters or is too long
|
|
128
|
-
*/
|
|
129
|
-
export function morse(value: string): string {
|
|
130
|
-
checkText(value);
|
|
131
|
-
return value
|
|
132
|
-
.toUpperCase()
|
|
133
|
-
.split(' ')
|
|
134
|
-
.map((word) =>
|
|
135
|
-
word
|
|
136
|
-
.split('')
|
|
137
|
-
.map((c) => {
|
|
138
|
-
if (c === '\n' || c === '\t') return '';
|
|
139
|
-
const code = MORSE_TABLE[c];
|
|
140
|
-
if (!code) throw new Error(`Unsupported character in Morse code: '${c}'`);
|
|
141
|
-
return code;
|
|
142
|
-
})
|
|
143
|
-
.filter(Boolean)
|
|
144
|
-
.join(' '),
|
|
145
|
-
)
|
|
146
|
-
.join(' / ');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Converts a Morse code string back to plain text.
|
|
151
|
-
*
|
|
152
|
-
* @param value - Morse code string (letters separated by spaces, words by " / ")
|
|
153
|
-
* @returns Decoded plain text string
|
|
154
|
-
* @throws Error if the Morse code contains an unrecognized sequence or is too long
|
|
155
|
-
*/
|
|
156
|
-
export function unmorse(value: string): string {
|
|
157
|
-
checkText(value);
|
|
158
|
-
return value
|
|
159
|
-
.split(' / ')
|
|
160
|
-
.map((word) =>
|
|
161
|
-
word
|
|
162
|
-
.split(' ')
|
|
163
|
-
.map((code) => {
|
|
164
|
-
if (!code) return '';
|
|
165
|
-
const char = MORSE_REVERSE[code];
|
|
166
|
-
if (!char) throw new Error(`Unsupported Morse sequence: '${code}'`);
|
|
167
|
-
return char;
|
|
168
|
-
})
|
|
169
|
-
.join(''),
|
|
170
|
-
)
|
|
171
|
-
.join(' ');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Applies the ROT13 substitution cipher to a string.
|
|
176
|
-
*
|
|
177
|
-
* @param value - The string to encode
|
|
178
|
-
* @returns ROT13-encoded string (applying it twice restores the original)
|
|
179
|
-
* @throws Error if value is missing, not a string, or too long
|
|
180
|
-
*/
|
|
181
|
-
export function rot13(value: string): string {
|
|
182
|
-
checkText(value);
|
|
183
|
-
return value.replace(/[a-zA-Z]/g, (c) => {
|
|
184
|
-
const base = c <= 'Z' ? 65 : 97;
|
|
185
|
-
return String.fromCharCode(((c.charCodeAt(0) - base + 13) % 26) + base);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Applies the Caesar cipher by shifting alphabetic characters by a given amount.
|
|
191
|
-
*
|
|
192
|
-
* @param value - The string to encode
|
|
193
|
-
* @param shift - Number of positions to shift (can be negative for left shift)
|
|
194
|
-
* @returns Caesar-shifted string
|
|
195
|
-
* @throws Error if value is missing or shift is not a number
|
|
196
|
-
*/
|
|
197
|
-
export function caesar(value: string, shift: string): string {
|
|
198
|
-
checkText(value);
|
|
199
|
-
const n = Number(shift);
|
|
200
|
-
if (isNaN(n)) throw new Error('Shift must be a number');
|
|
201
|
-
const s = ((n % 26) + 26) % 26;
|
|
202
|
-
return value.replace(/[a-zA-Z]/g, (c) => {
|
|
203
|
-
const base = c <= 'Z' ? 65 : 97;
|
|
204
|
-
return String.fromCharCode(((c.charCodeAt(0) - base + s) % 26) + base);
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Converts a string to its binary representation, one byte per character.
|
|
210
|
-
*
|
|
211
|
-
* @param value - The string to convert
|
|
212
|
-
* @returns Space-separated 8-bit binary groups (one per character)
|
|
213
|
-
* @throws Error if value is missing, not a string, or too long
|
|
214
|
-
*/
|
|
215
|
-
export function binary(value: string): string {
|
|
216
|
-
checkText(value);
|
|
217
|
-
return value
|
|
218
|
-
.split('')
|
|
219
|
-
.map((c) => c.charCodeAt(0).toString(2).padStart(8, '0'))
|
|
220
|
-
.join(' ');
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Converts a binary string back to plain text.
|
|
225
|
-
*
|
|
226
|
-
* @param value - Space-separated 8-bit binary groups
|
|
227
|
-
* @returns Decoded string
|
|
228
|
-
* @throws Error if value contains non-binary characters or groups are not 8 bits wide
|
|
229
|
-
*/
|
|
230
|
-
export function unbinary(value: string): string {
|
|
231
|
-
checkText(value);
|
|
232
|
-
if (!/^[01\s]+$/.test(value)) throw new Error('Invalid binary string');
|
|
233
|
-
return value
|
|
234
|
-
.trim()
|
|
235
|
-
.split(/\s+/)
|
|
236
|
-
.map((b) => {
|
|
237
|
-
if (b.length !== 8) throw new Error('Each binary group must contain 8 bits');
|
|
238
|
-
return String.fromCharCode(parseInt(b, 2));
|
|
239
|
-
})
|
|
240
|
-
.join('');
|
|
241
|
-
}
|
package/src/modules/v4/geo.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export interface GeoResult {
|
|
2
|
-
distance: { km: number; miles: number; nauticalMiles: number };
|
|
3
|
-
bearing: { degrees: number; cardinal: string };
|
|
4
|
-
from: { lat: number; lon: number };
|
|
5
|
-
to: { lat: number; lon: number };
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const EARTH_RADIUS_KM = 6371;
|
|
9
|
-
const CARDINALS = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'];
|
|
10
|
-
|
|
11
|
-
function toRad(deg: number): number {
|
|
12
|
-
return (deg * Math.PI) / 180;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function toDeg(rad: number): number {
|
|
16
|
-
return (rad * 180) / Math.PI;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function parseCoord(value: string, name: string, min: number, max: number): number {
|
|
20
|
-
const n = Number(value);
|
|
21
|
-
if (isNaN(n)) throw new Error(`${name} must be a number`);
|
|
22
|
-
if (n < min || n > max) throw new Error(`${name} must be between ${min} and ${max}`);
|
|
23
|
-
return n;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Calculates the great-circle distance and bearing between two geographic coordinates.
|
|
28
|
-
*
|
|
29
|
-
* @param lat1 - Latitude of the first point (-90 to 90)
|
|
30
|
-
* @param lon1 - Longitude of the first point (-180 to 180)
|
|
31
|
-
* @param lat2 - Latitude of the second point (-90 to 90)
|
|
32
|
-
* @param lon2 - Longitude of the second point (-180 to 180)
|
|
33
|
-
* @returns Distance in km/miles/nautical miles, compass bearing, and both coordinates
|
|
34
|
-
* @throws Error if any coordinate is out of range or not a number
|
|
35
|
-
*/
|
|
36
|
-
export default function geo(lat1: string, lon1: string, lat2: string, lon2: string): GeoResult {
|
|
37
|
-
const a = parseCoord(lat1, 'lat1', -90, 90);
|
|
38
|
-
const b = parseCoord(lon1, 'lon1', -180, 180);
|
|
39
|
-
const c = parseCoord(lat2, 'lat2', -90, 90);
|
|
40
|
-
const d = parseCoord(lon2, 'lon2', -180, 180);
|
|
41
|
-
|
|
42
|
-
const dLat = toRad(c - a);
|
|
43
|
-
const dLon = toRad(d - b);
|
|
44
|
-
const sa = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(a)) * Math.cos(toRad(c)) * Math.sin(dLon / 2) ** 2;
|
|
45
|
-
const distance = 2 * EARTH_RADIUS_KM * Math.asin(Math.sqrt(sa));
|
|
46
|
-
|
|
47
|
-
const y = Math.sin(toRad(d - b)) * Math.cos(toRad(c));
|
|
48
|
-
const x =
|
|
49
|
-
Math.cos(toRad(a)) * Math.sin(toRad(c)) - Math.sin(toRad(a)) * Math.cos(toRad(c)) * Math.cos(toRad(d - b));
|
|
50
|
-
const bearing = (toDeg(Math.atan2(y, x)) + 360) % 360;
|
|
51
|
-
const cardinal = CARDINALS[Math.round(bearing / 22.5) % 16]!;
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
distance: {
|
|
55
|
-
km: +distance.toFixed(3),
|
|
56
|
-
miles: +(distance * 0.621371).toFixed(3),
|
|
57
|
-
nauticalMiles: +(distance * 0.539957).toFixed(3),
|
|
58
|
-
},
|
|
59
|
-
bearing: { degrees: +bearing.toFixed(2), cardinal },
|
|
60
|
-
from: { lat: a, lon: b },
|
|
61
|
-
to: { lat: c, lon: d },
|
|
62
|
-
};
|
|
63
|
-
}
|
package/src/modules/v4/hash.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createHash, getHashes } from 'crypto';
|
|
2
|
-
|
|
3
|
-
export interface HashResult {
|
|
4
|
-
method: string;
|
|
5
|
-
hash: string;
|
|
6
|
-
encoding: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const ENCODINGS = new Set(['hex', 'base64']);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Hashes a text string using the specified algorithm and encoding.
|
|
13
|
-
*
|
|
14
|
-
* @param text - The text to hash
|
|
15
|
-
* @param method - Hashing algorithm (e.g. "sha256", "md5")
|
|
16
|
-
* @param encoding - Output encoding: "hex" (default) or "base64"
|
|
17
|
-
* @returns Object containing the method, hash result, and encoding used
|
|
18
|
-
* @throws Error if text is missing, the method is unsupported, or the encoding is invalid
|
|
19
|
-
*/
|
|
20
|
-
export default function hash(text: string, method: string, encoding: string = 'hex'): HashResult {
|
|
21
|
-
if (!text) throw new Error('Text is required');
|
|
22
|
-
|
|
23
|
-
const methods = getHashes();
|
|
24
|
-
if (!methods.includes(method)) throw new Error(`Unsupported method. Use one of: ${methods.join(', ')}`);
|
|
25
|
-
|
|
26
|
-
if (!ENCODINGS.has(encoding)) throw new Error('Encoding must be one of: hex, base64');
|
|
27
|
-
|
|
28
|
-
const result = createHash(method)
|
|
29
|
-
.update(text)
|
|
30
|
-
.digest(encoding as 'hex' | 'base64');
|
|
31
|
-
return { method, hash: result, encoding };
|
|
32
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import ical from 'ical.js';
|
|
2
|
-
|
|
3
|
-
import { formatDate } from '../../utils/helpers.js';
|
|
4
|
-
|
|
5
|
-
interface CalendarEvent {
|
|
6
|
-
summary: string[] | string;
|
|
7
|
-
subject?: string;
|
|
8
|
-
teacher?: string;
|
|
9
|
-
classes?: string[];
|
|
10
|
-
type?: string;
|
|
11
|
-
start: string;
|
|
12
|
-
end: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function blocked(hostname: string): boolean {
|
|
16
|
-
const list = ['localhost', '127.0.0.1', '0.0.0.0', '[::1]', 'metadata.google.internal'];
|
|
17
|
-
if (list.includes(hostname)) return true;
|
|
18
|
-
|
|
19
|
-
const parts = hostname.split('.').map(Number);
|
|
20
|
-
if (parts.length === 4 && parts.every((n) => !isNaN(n))) {
|
|
21
|
-
if (parts[0] === 10) return true;
|
|
22
|
-
if (parts[0] === 172 && parts[1]! >= 16 && parts[1]! <= 31) return true;
|
|
23
|
-
if (parts[0] === 192 && parts[1] === 168) return true;
|
|
24
|
-
if (parts[0] === 169 && parts[1] === 254) return true;
|
|
25
|
-
if (parts[0] === 0) return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Fetches and parses an ICS calendar from a Hyperplanning URL, filtering out past events.
|
|
33
|
-
*
|
|
34
|
-
* @param url - HTTPS URL to the ICS calendar
|
|
35
|
-
* @param detail - Level of detail: "full" (subject/teacher/classes), "list" (summary/times), or default (summary only)
|
|
36
|
-
* @returns Array of calendar events sorted by start time, excluding past events
|
|
37
|
-
* @throws Error if the URL is invalid, uses HTTP, points to a private host, or does not return a valid ICS file
|
|
38
|
-
*/
|
|
39
|
-
export default async function hyperplanning(url: string, detail?: string): Promise<CalendarEvent[]> {
|
|
40
|
-
let parsed: URL;
|
|
41
|
-
try {
|
|
42
|
-
parsed = new URL(url);
|
|
43
|
-
} catch {
|
|
44
|
-
throw new Error('Invalid URL.');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (parsed.protocol !== 'https:') throw new Error('Only HTTPS URLs are allowed.');
|
|
48
|
-
if (blocked(parsed.hostname)) throw new Error('Access to private/internal hosts is not allowed.');
|
|
49
|
-
|
|
50
|
-
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
51
|
-
|
|
52
|
-
if (!response.ok || !(response.headers.get('content-type') || '').includes('text/calendar')) {
|
|
53
|
-
throw new Error('Invalid ICS file format.');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const events: CalendarEvent[] = new ical.Component(ical.parse(await response.text()))
|
|
57
|
-
.getAllSubcomponents('vevent')
|
|
58
|
-
.map((e: ical.Component) => {
|
|
59
|
-
const evt = new ical.Event(e);
|
|
60
|
-
const summary = (evt.summary || '').split(' ').filter((part: string) => part !== '-');
|
|
61
|
-
const start = formatDate(evt.startDate.toJSDate());
|
|
62
|
-
const end = formatDate(evt.endDate.toJSDate());
|
|
63
|
-
|
|
64
|
-
if (detail === 'full') {
|
|
65
|
-
const desc = (evt.description || '').split('\n').map((l: string) => l.trim());
|
|
66
|
-
const extract = (p: string) => (desc.find((l: string) => l.startsWith(p)) || '').replace(p, '').trim();
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
summary,
|
|
70
|
-
subject: extract('Matière :'),
|
|
71
|
-
teacher: extract('Enseignant :'),
|
|
72
|
-
classes: extract('Promotions :')
|
|
73
|
-
.split(', ')
|
|
74
|
-
.map((c: string) => c.trim()),
|
|
75
|
-
type: extract('Salle :') || undefined,
|
|
76
|
-
start,
|
|
77
|
-
end,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (detail === 'list') return { summary, start, end };
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
summary: evt.summary || '',
|
|
85
|
-
start,
|
|
86
|
-
end,
|
|
87
|
-
};
|
|
88
|
-
})
|
|
89
|
-
.sort((a: CalendarEvent, b: CalendarEvent) => new Date(a.start).getTime() - new Date(b.start).getTime())
|
|
90
|
-
.filter((e: CalendarEvent) => new Date(e.end) >= new Date());
|
|
91
|
-
|
|
92
|
-
return events;
|
|
93
|
-
}
|