@20syldev/api 4.5.0 → 4.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 (75) hide show
  1. package/README.md +11 -4
  2. package/eslint.config.js +4 -0
  3. package/package.json +3 -2
  4. package/src/app.ts +7 -6
  5. package/src/config/env.ts +1 -0
  6. package/src/config/versions.ts +10 -2
  7. package/src/middleware/error.ts +2 -1
  8. package/src/middleware/json.ts +1 -1
  9. package/src/middleware/logger.ts +2 -1
  10. package/src/middleware/ratelimit.ts +4 -3
  11. package/src/middleware/version.ts +2 -1
  12. package/src/modules/v3.js +1 -1
  13. package/src/modules/v4/address.ts +413 -0
  14. package/src/modules/v4/agent.ts +104 -0
  15. package/src/modules/v4/algorithms.ts +79 -0
  16. package/src/modules/v4/captcha.ts +8 -0
  17. package/src/modules/v4/chat.ts +10 -2
  18. package/src/modules/v4/color.ts +8 -1
  19. package/src/modules/v4/convert.ts +9 -0
  20. package/src/modules/v4/dice.ts +7 -0
  21. package/src/modules/v4/domain.ts +6 -1
  22. package/src/modules/v4/encode.ts +71 -0
  23. package/src/modules/v4/geo.ts +10 -0
  24. package/src/modules/v4/hash.ts +10 -1
  25. package/src/modules/v4/hyperplanning.ts +10 -1
  26. package/src/modules/v4/ip.ts +134 -0
  27. package/src/modules/v4/levenshtein.ts +8 -0
  28. package/src/modules/v4/palette.ts +9 -1
  29. package/src/modules/v4/password.ts +381 -0
  30. package/src/modules/v4/personal.ts +9 -16
  31. package/src/modules/v4/placeholder.ts +8 -0
  32. package/src/modules/v4/qrcode.ts +9 -1
  33. package/src/modules/v4/statistics.ts +7 -0
  34. package/src/modules/v4/text.ts +30 -0
  35. package/src/modules/v4/tic_tac_toe.ts +11 -2
  36. package/src/modules/v4/time.ts +11 -0
  37. package/src/modules/v4/token.ts +18 -8
  38. package/src/modules/v4/username.ts +5 -0
  39. package/src/modules/v4/validate.ts +21 -0
  40. package/src/modules/v4.ts +5 -1
  41. package/src/routes/delete.ts +2 -1
  42. package/src/routes/get.ts +115 -7
  43. package/src/routes/index.ts +4 -3
  44. package/src/routes/patch.ts +2 -1
  45. package/src/routes/post.ts +5 -4
  46. package/src/storage/index.ts +1 -1
  47. package/src/utils/response.ts +1 -0
  48. package/tests/integration/api.test.ts +142 -2
  49. package/tests/unit/address.test.ts +84 -0
  50. package/tests/unit/agent.test.ts +113 -0
  51. package/tests/unit/algorithms.test.ts +2 -1
  52. package/tests/unit/captcha.test.ts +2 -1
  53. package/tests/unit/chat.test.ts +2 -1
  54. package/tests/unit/color.test.ts +2 -1
  55. package/tests/unit/convert.test.ts +2 -1
  56. package/tests/unit/dice.test.ts +2 -1
  57. package/tests/unit/domain.test.ts +2 -1
  58. package/tests/unit/encode.test.ts +8 -7
  59. package/tests/unit/geo.test.ts +2 -1
  60. package/tests/unit/hash.test.ts +2 -1
  61. package/tests/unit/hyperplanning.test.ts +2 -1
  62. package/tests/unit/ip.test.ts +140 -0
  63. package/tests/unit/levenshtein.test.ts +2 -1
  64. package/tests/unit/palette.test.ts +2 -1
  65. package/tests/unit/password.test.ts +86 -0
  66. package/tests/unit/personal.test.ts +2 -1
  67. package/tests/unit/placeholder.test.ts +2 -1
  68. package/tests/unit/qrcode.test.ts +2 -1
  69. package/tests/unit/statistics.test.ts +2 -1
  70. package/tests/unit/text.test.ts +3 -2
  71. package/tests/unit/tic_tac_toe.test.ts +2 -1
  72. package/tests/unit/time.test.ts +2 -1
  73. package/tests/unit/token.test.ts +2 -1
  74. package/tests/unit/username.test.ts +2 -1
  75. package/tests/unit/validate.test.ts +3 -2
@@ -0,0 +1,113 @@
1
+ import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
4
+ import agent from '../../src/modules/v4/agent.js';
5
+
6
+ const CHROME_MAC =
7
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
8
+ const FIREFOX_WIN = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0';
9
+ const SAFARI_IPHONE =
10
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
11
+ const EDGE_WIN =
12
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0';
13
+ const GOOGLEBOT = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)';
14
+ const IPAD =
15
+ 'Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1';
16
+
17
+ describe('agent', () => {
18
+ describe('browser detection', () => {
19
+ test('Chrome on macOS', () => {
20
+ const r = agent(CHROME_MAC);
21
+ assert.equal(r.browser.name, 'Chrome');
22
+ assert.equal(r.browser.major, '120');
23
+ });
24
+
25
+ test('Firefox on Windows', () => {
26
+ const r = agent(FIREFOX_WIN);
27
+ assert.equal(r.browser.name, 'Firefox');
28
+ assert.equal(r.browser.major, '121');
29
+ });
30
+
31
+ test('Safari on iPhone', () => {
32
+ const r = agent(SAFARI_IPHONE);
33
+ assert.equal(r.browser.name, 'Safari');
34
+ });
35
+
36
+ test('Edge detected before Chrome (both present in UA)', () => {
37
+ const r = agent(EDGE_WIN);
38
+ assert.equal(r.browser.name, 'Edge');
39
+ });
40
+
41
+ test('unknown browser returns unknown', () => {
42
+ const r = agent('UnknownBrowser/1.0');
43
+ assert.equal(r.browser.name, 'unknown');
44
+ });
45
+ });
46
+
47
+ describe('OS detection', () => {
48
+ test('macOS from Chrome UA', () => {
49
+ const r = agent(CHROME_MAC);
50
+ assert.equal(r.os.name, 'macOS');
51
+ assert.equal(r.os.version, '10.15.7');
52
+ });
53
+
54
+ test('Windows 10/11 from Firefox UA', () => {
55
+ const r = agent(FIREFOX_WIN);
56
+ assert.equal(r.os.name, 'Windows 10/11');
57
+ });
58
+
59
+ test('iOS from iPhone UA', () => {
60
+ const r = agent(SAFARI_IPHONE);
61
+ assert.equal(r.os.name, 'iOS');
62
+ assert.equal(r.os.version, '17.0');
63
+ });
64
+ });
65
+
66
+ describe('device detection', () => {
67
+ test('desktop from Chrome macOS', () => {
68
+ assert.equal(agent(CHROME_MAC).device.type, 'desktop');
69
+ });
70
+
71
+ test('mobile from iPhone UA', () => {
72
+ assert.equal(agent(SAFARI_IPHONE).device.type, 'mobile');
73
+ });
74
+
75
+ test('tablet from iPad UA', () => {
76
+ assert.equal(agent(IPAD).device.type, 'tablet');
77
+ });
78
+
79
+ test('Apple vendor from iPhone', () => {
80
+ assert.equal(agent(SAFARI_IPHONE).device.vendor, 'Apple');
81
+ });
82
+ });
83
+
84
+ describe('engine detection', () => {
85
+ test('Chrome uses Blink', () => {
86
+ assert.equal(agent(CHROME_MAC).engine.name, 'Blink');
87
+ });
88
+
89
+ test('Firefox uses Gecko', () => {
90
+ assert.equal(agent(FIREFOX_WIN).engine.name, 'Gecko');
91
+ });
92
+
93
+ test('Edge uses Blink', () => {
94
+ assert.equal(agent(EDGE_WIN).engine.name, 'Blink');
95
+ });
96
+ });
97
+
98
+ describe('bot detection', () => {
99
+ test('Googlebot is a bot', () => {
100
+ assert.equal(agent(GOOGLEBOT).bot, true);
101
+ });
102
+
103
+ test('Chrome is not a bot', () => {
104
+ assert.equal(agent(CHROME_MAC).bot, false);
105
+ });
106
+ });
107
+
108
+ describe('errors', () => {
109
+ test('throws on empty string', () => {
110
+ assert.throws(() => agent(''), /required/);
111
+ });
112
+ });
113
+ });
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import {
4
5
  anagram,
5
6
  factorial,
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import captcha from '../../src/modules/v4/captcha.js';
4
5
 
5
6
  const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47]);
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import chat from '../../src/modules/v4/chat.js';
4
5
  import type { ChatStorage } from '../../src/types/storage.js';
5
6
 
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import color from '../../src/modules/v4/color.js';
4
5
 
5
6
  describe('color', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import convert from '../../src/modules/v4/convert.js';
4
5
 
5
6
  describe('convert', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import dice from '../../src/modules/v4/dice.js';
4
5
 
5
6
  describe('dice', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import domain from '../../src/modules/v4/domain.js';
4
5
 
5
6
  describe('domain', () => {
@@ -1,16 +1,17 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import {
4
- base64encode,
5
5
  base64decode,
6
- urlencode,
7
- urldecode,
6
+ base64encode,
7
+ binary,
8
+ caesar,
8
9
  morse,
9
- unmorse,
10
10
  rot13,
11
- caesar,
12
- binary,
13
11
  unbinary,
12
+ unmorse,
13
+ urldecode,
14
+ urlencode,
14
15
  } from '../../src/modules/v4/encode.js';
15
16
 
16
17
  describe('encode', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import geo from '../../src/modules/v4/geo.js';
4
5
 
5
6
  describe('geo', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import hash from '../../src/modules/v4/hash.js';
4
5
 
5
6
  describe('hash', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe, before, after } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { after, before, describe, test } from 'node:test';
3
+
3
4
  import hyperplanning from '../../src/modules/v4/hyperplanning.js';
4
5
 
5
6
  const ORIGINAL_FETCH = globalThis.fetch;
@@ -0,0 +1,140 @@
1
+ import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
4
+ import ip from '../../src/modules/v4/ip.js';
5
+
6
+ describe('ip', () => {
7
+ describe('IPv4 — type detection', () => {
8
+ test('public IP returns public type and class A', () => {
9
+ const result = ip('8.8.8.8');
10
+ assert.equal(result.version, 'IPv4');
11
+ assert.equal(result.type, 'public');
12
+ assert.equal(result.class, 'A');
13
+ });
14
+
15
+ test('private 10.x.x.x', () => {
16
+ const result = ip('10.0.0.1');
17
+ assert.equal(result.type, 'private');
18
+ assert.equal(result.range, '10.0.0.0/8');
19
+ });
20
+
21
+ test('private 172.16-31.x.x', () => {
22
+ const result = ip('172.16.0.1');
23
+ assert.equal(result.type, 'private');
24
+ assert.equal(result.range, '172.16.0.0/12');
25
+ });
26
+
27
+ test('private 192.168.x.x', () => {
28
+ const result = ip('192.168.1.1');
29
+ assert.equal(result.type, 'private');
30
+ assert.equal(result.class, 'C');
31
+ assert.equal(result.range, '192.168.0.0/16');
32
+ });
33
+
34
+ test('loopback 127.0.0.1', () => {
35
+ const result = ip('127.0.0.1');
36
+ assert.equal(result.type, 'loopback');
37
+ assert.equal(result.range, '127.0.0.0/8');
38
+ });
39
+
40
+ test('link-local 169.254.x.x', () => {
41
+ const result = ip('169.254.1.1');
42
+ assert.equal(result.type, 'link-local');
43
+ });
44
+
45
+ test('multicast 224.x.x.x', () => {
46
+ const result = ip('224.0.0.1');
47
+ assert.equal(result.type, 'multicast');
48
+ });
49
+
50
+ test('broadcast 255.255.255.255', () => {
51
+ const result = ip('255.255.255.255');
52
+ assert.equal(result.type, 'broadcast');
53
+ assert.equal(result.class, 'E');
54
+ });
55
+ });
56
+
57
+ describe('IPv4 — representations', () => {
58
+ test('binary of 192.168.1.1', () => {
59
+ const result = ip('192.168.1.1');
60
+ assert.equal(result.binary, '11000000.10101000.00000001.00000001');
61
+ });
62
+
63
+ test('decimal of 192.168.1.1', () => {
64
+ const result = ip('192.168.1.1');
65
+ assert.equal(result.decimal, 3232235777);
66
+ });
67
+
68
+ test('decimal of 8.8.8.8', () => {
69
+ const result = ip('8.8.8.8');
70
+ assert.equal(result.decimal, 134744072);
71
+ });
72
+
73
+ test('reverse DNS of 192.168.1.1', () => {
74
+ const result = ip('192.168.1.1');
75
+ assert.equal(result.reverse, '1.1.168.192.in-addr.arpa');
76
+ });
77
+
78
+ test('class B for 128.x', () => {
79
+ assert.equal(ip('128.0.0.1').class, 'B');
80
+ });
81
+
82
+ test('class C for 192.x (non-private)', () => {
83
+ assert.equal(ip('200.0.0.1').class, 'C');
84
+ });
85
+ });
86
+
87
+ describe('IPv6', () => {
88
+ test('loopback ::1', () => {
89
+ const result = ip('::1');
90
+ assert.equal(result.version, 'IPv6');
91
+ assert.equal(result.type, 'loopback');
92
+ assert.equal(result.range, '::1/128');
93
+ });
94
+
95
+ test('link-local fe80::1', () => {
96
+ const result = ip('fe80::1');
97
+ assert.equal(result.type, 'link-local');
98
+ assert.equal(result.range, 'fe80::/10');
99
+ });
100
+
101
+ test('unique-local fc00::1', () => {
102
+ const result = ip('fc00::1');
103
+ assert.equal(result.type, 'private');
104
+ assert.equal(result.range, 'fc00::/7');
105
+ });
106
+
107
+ test('multicast ff02::1', () => {
108
+ const result = ip('ff02::1');
109
+ assert.equal(result.type, 'multicast');
110
+ });
111
+
112
+ test(':: expansion produces 8 groups', () => {
113
+ const result = ip('::1');
114
+ assert.equal(result.ip.split(':').length, 8);
115
+ });
116
+
117
+ test('reverse DNS ends in .ip6.arpa', () => {
118
+ const result = ip('::1');
119
+ assert.ok(result.reverse.endsWith('.ip6.arpa'));
120
+ });
121
+ });
122
+
123
+ describe('errors', () => {
124
+ test('throws on empty string', () => {
125
+ assert.throws(() => ip(''), /required/);
126
+ });
127
+
128
+ test('throws on invalid IPv4 octet > 255', () => {
129
+ assert.throws(() => ip('256.0.0.1'), /Invalid IPv4/);
130
+ });
131
+
132
+ test('throws on incomplete IPv4', () => {
133
+ assert.throws(() => ip('192.168.1'), /Invalid IPv4/);
134
+ });
135
+
136
+ test('throws on plain string', () => {
137
+ assert.throws(() => ip('notanip'), /Invalid IP address format/);
138
+ });
139
+ });
140
+ });
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import levenshtein from '../../src/modules/v4/levenshtein.js';
4
5
 
5
6
  describe('levenshtein', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import palette from '../../src/modules/v4/palette.js';
4
5
 
5
6
  describe('palette', () => {
@@ -0,0 +1,86 @@
1
+ import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
4
+ import password from '../../src/modules/v4/password.js';
5
+
6
+ describe('password', () => {
7
+ describe('random mode', () => {
8
+ test('default returns one password of length 16', () => {
9
+ const r = password();
10
+ assert.equal(r.passwords.length, 1);
11
+ assert.equal(r.passwords[0]!.length, 16);
12
+ assert.equal(r.type, 'random');
13
+ assert.equal(r.length, 16);
14
+ });
15
+
16
+ test('length is respected', () => {
17
+ const r = password('random', 32);
18
+ assert.equal(r.passwords[0]!.length, 32);
19
+ });
20
+
21
+ test('no symbols when symbols=false', () => {
22
+ const r = password('random', 64, { symbols: false });
23
+ assert.ok(!/[!@#$%^&*()\-_=+[\]{}|;:,.<>?]/.test(r.passwords[0]!));
24
+ });
25
+
26
+ test('only digits when only digits enabled', () => {
27
+ const r = password('random', 16, { uppercase: false, lowercase: false, digits: true, symbols: false });
28
+ assert.ok(/^\d+$/.test(r.passwords[0]!));
29
+ });
30
+
31
+ test('exclude chars are absent from password', () => {
32
+ const r = password('random', 64, { exclude: 'aeiou' });
33
+ assert.ok(!/[aeiou]/.test(r.passwords[0]!));
34
+ });
35
+
36
+ test('count=5 returns 5 passwords', () => {
37
+ const r = password('random', 16, { count: 5 });
38
+ assert.equal(r.passwords.length, 5);
39
+ });
40
+
41
+ test('entropy and strength are present', () => {
42
+ const r = password();
43
+ assert.ok(typeof r.entropy === 'number');
44
+ assert.ok(['weak', 'moderate', 'strong', 'very_strong'].includes(r.strength));
45
+ });
46
+ });
47
+
48
+ describe('passphrase mode', () => {
49
+ test('returns words joined by separator', () => {
50
+ const r = password('passphrase', 4, { separator: '-' });
51
+ assert.equal(r.type, 'passphrase');
52
+ const words = r.passwords[0]!.split('-');
53
+ assert.equal(words.length, 4);
54
+ });
55
+
56
+ test('custom separator is used', () => {
57
+ const r = password('passphrase', 3, { separator: '.' });
58
+ assert.ok(r.passwords[0]!.includes('.'));
59
+ });
60
+ });
61
+
62
+ describe('errors', () => {
63
+ test('length below 8 throws', () => {
64
+ assert.throws(() => password('random', 4), /Length must be between/);
65
+ });
66
+
67
+ test('length above 128 throws', () => {
68
+ assert.throws(() => password('random', 200), /Length must be between/);
69
+ });
70
+
71
+ test('no charset active throws', () => {
72
+ assert.throws(
73
+ () => password('random', 16, { uppercase: false, lowercase: false, digits: false, symbols: false }),
74
+ /At least one character set/,
75
+ );
76
+ });
77
+
78
+ test('count above 20 throws', () => {
79
+ assert.throws(() => password('random', 16, { count: 21 }), /Count must be between/);
80
+ });
81
+
82
+ test('invalid type throws', () => {
83
+ assert.throws(() => password('invalid'), /Type must be/);
84
+ });
85
+ });
86
+ });
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import personal from '../../src/modules/v4/personal.js';
4
5
 
5
6
  describe('personal', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import placeholder from '../../src/modules/v4/placeholder.js';
4
5
 
5
6
  describe('placeholder', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import qrcode from '../../src/modules/v4/qrcode.js';
4
5
 
5
6
  const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47]);
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import statistics from '../../src/modules/v4/statistics.js';
4
5
 
5
6
  describe('statistics', () => {
@@ -1,6 +1,7 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
3
- import { slug, stats, lorem, number } from '../../src/modules/v4/text.js';
2
+ import { describe, test } from 'node:test';
3
+
4
+ import { lorem, number, slug, stats } from '../../src/modules/v4/text.js';
4
5
 
5
6
  describe('text', () => {
6
7
  describe('slug', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import tic_tac_toe from '../../src/modules/v4/tic_tac_toe.js';
4
5
  import type { TicTacToeStorage } from '../../src/types/storage.js';
5
6
 
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import time from '../../src/modules/v4/time.js';
4
5
 
5
6
  describe('time', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import token from '../../src/modules/v4/token.js';
4
5
 
5
6
  describe('token', () => {
@@ -1,5 +1,6 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
2
+ import { describe, test } from 'node:test';
3
+
3
4
  import username from '../../src/modules/v4/username.js';
4
5
 
5
6
  describe('username', () => {
@@ -1,6 +1,7 @@
1
- import { test, describe } from 'node:test';
2
1
  import { strict as assert } from 'node:assert';
3
- import { luhn, iban, email } from '../../src/modules/v4/validate.js';
2
+ import { describe, test } from 'node:test';
3
+
4
+ import { email, iban, luhn } from '../../src/modules/v4/validate.js';
4
5
 
5
6
  describe('validate', () => {
6
7
  describe('luhn', () => {