@20syldev/api 4.8.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/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 -121
- package/src/constants.ts +0 -61
- 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/address.ts +0 -412
- package/src/modules/v4/agent.ts +0 -104
- 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/cron.ts +0 -221
- 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 -64
- package/src/modules/v4/hash.ts +0 -32
- package/src/modules/v4/hyperplanning.ts +0 -93
- package/src/modules/v4/ip.ts +0 -134
- package/src/modules/v4/levenshtein.ts +0 -46
- package/src/modules/v4/palette.ts +0 -71
- package/src/modules/v4/password.ts +0 -379
- 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/regex.ts +0 -67
- 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 -149
- 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 -29
- package/src/routes/delete.ts +0 -72
- package/src/routes/get.ts +0 -856
- 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 -772
- 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/cron.test.ts +0 -110
- 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/regex.test.ts +0 -95
- 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 -115
- 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,412 +0,0 @@
|
|
|
1
|
-
import { MAX_ADDRESS_COUNT } from '../../constants.js';
|
|
2
|
-
import { random, randomNumber } from '../../utils/helpers.js';
|
|
3
|
-
|
|
4
|
-
interface CountryData {
|
|
5
|
-
name: string;
|
|
6
|
-
streetTypes: string[];
|
|
7
|
-
streetNames: string[];
|
|
8
|
-
cities: string[];
|
|
9
|
-
regions: string[];
|
|
10
|
-
zipFormat: () => string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function randomChar(chars: string): string {
|
|
14
|
-
return chars[Math.floor(Math.random() * chars.length)]!;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
18
|
-
|
|
19
|
-
const countries: Record<string, CountryData> = {
|
|
20
|
-
fr: {
|
|
21
|
-
name: 'France',
|
|
22
|
-
streetTypes: ['Rue', 'Avenue', 'Boulevard', 'Allée', 'Impasse', 'Place', 'Chemin', 'Route', 'Voie', 'Passage'],
|
|
23
|
-
streetNames: [
|
|
24
|
-
'de la Paix',
|
|
25
|
-
'Victor Hugo',
|
|
26
|
-
'Jean Jaurès',
|
|
27
|
-
'de la République',
|
|
28
|
-
'du Général de Gaulle',
|
|
29
|
-
'de la Liberté',
|
|
30
|
-
'des Fleurs',
|
|
31
|
-
'du Moulin',
|
|
32
|
-
'de la Forêt',
|
|
33
|
-
'des Lilas',
|
|
34
|
-
'du Château',
|
|
35
|
-
'de la Mairie',
|
|
36
|
-
'de la Gare',
|
|
37
|
-
'du Commerce',
|
|
38
|
-
'de la Fontaine',
|
|
39
|
-
'de la Croix',
|
|
40
|
-
'des Vignes',
|
|
41
|
-
'du Marché',
|
|
42
|
-
"de l'Église",
|
|
43
|
-
'des Acacias',
|
|
44
|
-
],
|
|
45
|
-
cities: [
|
|
46
|
-
'Paris',
|
|
47
|
-
'Lyon',
|
|
48
|
-
'Marseille',
|
|
49
|
-
'Toulouse',
|
|
50
|
-
'Nice',
|
|
51
|
-
'Nantes',
|
|
52
|
-
'Strasbourg',
|
|
53
|
-
'Montpellier',
|
|
54
|
-
'Bordeaux',
|
|
55
|
-
'Lille',
|
|
56
|
-
'Rennes',
|
|
57
|
-
'Reims',
|
|
58
|
-
'Le Havre',
|
|
59
|
-
'Saint-Étienne',
|
|
60
|
-
'Toulon',
|
|
61
|
-
'Grenoble',
|
|
62
|
-
'Dijon',
|
|
63
|
-
'Angers',
|
|
64
|
-
'Nîmes',
|
|
65
|
-
'Villeurbanne',
|
|
66
|
-
],
|
|
67
|
-
regions: [
|
|
68
|
-
'Île-de-France',
|
|
69
|
-
'Auvergne-Rhône-Alpes',
|
|
70
|
-
"Provence-Alpes-Côte d'Azur",
|
|
71
|
-
'Occitanie',
|
|
72
|
-
'Hauts-de-France',
|
|
73
|
-
'Nouvelle-Aquitaine',
|
|
74
|
-
'Grand Est',
|
|
75
|
-
'Pays de la Loire',
|
|
76
|
-
'Bretagne',
|
|
77
|
-
'Normandie',
|
|
78
|
-
'Bourgogne-Franche-Comté',
|
|
79
|
-
'Centre-Val de Loire',
|
|
80
|
-
],
|
|
81
|
-
zipFormat: () => String(randomNumber(10000, 99999)).padStart(5, '0'),
|
|
82
|
-
},
|
|
83
|
-
us: {
|
|
84
|
-
name: 'United States',
|
|
85
|
-
streetTypes: ['Street', 'Avenue', 'Boulevard', 'Drive', 'Road', 'Lane', 'Court', 'Way', 'Place', 'Circle'],
|
|
86
|
-
streetNames: [
|
|
87
|
-
'Main',
|
|
88
|
-
'Oak',
|
|
89
|
-
'Maple',
|
|
90
|
-
'Cedar',
|
|
91
|
-
'Pine',
|
|
92
|
-
'Elm',
|
|
93
|
-
'Washington',
|
|
94
|
-
'Lincoln',
|
|
95
|
-
'Park',
|
|
96
|
-
'Lake',
|
|
97
|
-
'Hill',
|
|
98
|
-
'River',
|
|
99
|
-
'Sunset',
|
|
100
|
-
'Forest',
|
|
101
|
-
'Meadow',
|
|
102
|
-
'Valley',
|
|
103
|
-
'Highland',
|
|
104
|
-
'Willow',
|
|
105
|
-
'Spring',
|
|
106
|
-
'Church',
|
|
107
|
-
],
|
|
108
|
-
cities: [
|
|
109
|
-
'New York',
|
|
110
|
-
'Los Angeles',
|
|
111
|
-
'Chicago',
|
|
112
|
-
'Houston',
|
|
113
|
-
'Phoenix',
|
|
114
|
-
'Philadelphia',
|
|
115
|
-
'San Antonio',
|
|
116
|
-
'San Diego',
|
|
117
|
-
'Dallas',
|
|
118
|
-
'San Jose',
|
|
119
|
-
'Austin',
|
|
120
|
-
'Jacksonville',
|
|
121
|
-
'Fort Worth',
|
|
122
|
-
'Columbus',
|
|
123
|
-
'Charlotte',
|
|
124
|
-
'Indianapolis',
|
|
125
|
-
'San Francisco',
|
|
126
|
-
'Seattle',
|
|
127
|
-
'Denver',
|
|
128
|
-
'Nashville',
|
|
129
|
-
],
|
|
130
|
-
regions: [
|
|
131
|
-
'California',
|
|
132
|
-
'Texas',
|
|
133
|
-
'Florida',
|
|
134
|
-
'New York',
|
|
135
|
-
'Pennsylvania',
|
|
136
|
-
'Illinois',
|
|
137
|
-
'Ohio',
|
|
138
|
-
'Georgia',
|
|
139
|
-
'North Carolina',
|
|
140
|
-
'Michigan',
|
|
141
|
-
'New Jersey',
|
|
142
|
-
'Virginia',
|
|
143
|
-
'Washington',
|
|
144
|
-
'Arizona',
|
|
145
|
-
'Massachusetts',
|
|
146
|
-
'Tennessee',
|
|
147
|
-
'Indiana',
|
|
148
|
-
'Colorado',
|
|
149
|
-
'Missouri',
|
|
150
|
-
'Maryland',
|
|
151
|
-
],
|
|
152
|
-
zipFormat: () => String(randomNumber(10000, 99999)).padStart(5, '0'),
|
|
153
|
-
},
|
|
154
|
-
uk: {
|
|
155
|
-
name: 'United Kingdom',
|
|
156
|
-
streetTypes: ['Street', 'Road', 'Avenue', 'Lane', 'Close', 'Drive', 'Way', 'Court', 'Grove', 'Place'],
|
|
157
|
-
streetNames: [
|
|
158
|
-
'High',
|
|
159
|
-
'Church',
|
|
160
|
-
'Station',
|
|
161
|
-
'Park',
|
|
162
|
-
'Manor',
|
|
163
|
-
'Mill',
|
|
164
|
-
'Victoria',
|
|
165
|
-
'King',
|
|
166
|
-
'Queen',
|
|
167
|
-
'Albert',
|
|
168
|
-
'George',
|
|
169
|
-
'York',
|
|
170
|
-
'Oxford',
|
|
171
|
-
'Cambridge',
|
|
172
|
-
'Windsor',
|
|
173
|
-
'Richmond',
|
|
174
|
-
'Elm',
|
|
175
|
-
'Oak',
|
|
176
|
-
'Ash',
|
|
177
|
-
'Rose',
|
|
178
|
-
],
|
|
179
|
-
cities: [
|
|
180
|
-
'London',
|
|
181
|
-
'Birmingham',
|
|
182
|
-
'Manchester',
|
|
183
|
-
'Glasgow',
|
|
184
|
-
'Liverpool',
|
|
185
|
-
'Bristol',
|
|
186
|
-
'Sheffield',
|
|
187
|
-
'Leeds',
|
|
188
|
-
'Edinburgh',
|
|
189
|
-
'Leicester',
|
|
190
|
-
'Coventry',
|
|
191
|
-
'Bradford',
|
|
192
|
-
'Cardiff',
|
|
193
|
-
'Belfast',
|
|
194
|
-
'Nottingham',
|
|
195
|
-
'Kingston upon Hull',
|
|
196
|
-
'Newcastle',
|
|
197
|
-
'Stoke-on-Trent',
|
|
198
|
-
'Southampton',
|
|
199
|
-
'Derby',
|
|
200
|
-
],
|
|
201
|
-
regions: [
|
|
202
|
-
'England',
|
|
203
|
-
'Scotland',
|
|
204
|
-
'Wales',
|
|
205
|
-
'Northern Ireland',
|
|
206
|
-
'Greater London',
|
|
207
|
-
'South East',
|
|
208
|
-
'North West',
|
|
209
|
-
'East of England',
|
|
210
|
-
'West Midlands',
|
|
211
|
-
'South West',
|
|
212
|
-
'Yorkshire',
|
|
213
|
-
'East Midlands',
|
|
214
|
-
'North East',
|
|
215
|
-
],
|
|
216
|
-
zipFormat: () =>
|
|
217
|
-
`${randomChar(ALPHA)}${randomChar(ALPHA)}${randomNumber(1, 9)} ${randomNumber(1, 9)}${randomChar(ALPHA)}${randomChar(ALPHA)}`,
|
|
218
|
-
},
|
|
219
|
-
de: {
|
|
220
|
-
name: 'Germany',
|
|
221
|
-
streetTypes: ['Straße', 'Allee', 'Weg', 'Platz', 'Gasse', 'Ring', 'Damm', 'Ufer', 'Stieg', 'Pfad'],
|
|
222
|
-
streetNames: [
|
|
223
|
-
'Haupt',
|
|
224
|
-
'Bahnhof',
|
|
225
|
-
'Schul',
|
|
226
|
-
'Kirch',
|
|
227
|
-
'Garten',
|
|
228
|
-
'Berg',
|
|
229
|
-
'Wald',
|
|
230
|
-
'Wiesen',
|
|
231
|
-
'Tal',
|
|
232
|
-
'See',
|
|
233
|
-
'Bismarck',
|
|
234
|
-
'Goethe',
|
|
235
|
-
'Schiller',
|
|
236
|
-
'Kant',
|
|
237
|
-
'Hegel',
|
|
238
|
-
'Mozart',
|
|
239
|
-
'Beethoven',
|
|
240
|
-
'Bach',
|
|
241
|
-
'Brahms',
|
|
242
|
-
'Handel',
|
|
243
|
-
],
|
|
244
|
-
cities: [
|
|
245
|
-
'Berlin',
|
|
246
|
-
'Hamburg',
|
|
247
|
-
'Munich',
|
|
248
|
-
'Cologne',
|
|
249
|
-
'Frankfurt',
|
|
250
|
-
'Stuttgart',
|
|
251
|
-
'Düsseldorf',
|
|
252
|
-
'Leipzig',
|
|
253
|
-
'Dortmund',
|
|
254
|
-
'Essen',
|
|
255
|
-
'Bremen',
|
|
256
|
-
'Dresden',
|
|
257
|
-
'Hanover',
|
|
258
|
-
'Nuremberg',
|
|
259
|
-
'Duisburg',
|
|
260
|
-
'Bochum',
|
|
261
|
-
'Wuppertal',
|
|
262
|
-
'Bielefeld',
|
|
263
|
-
'Bonn',
|
|
264
|
-
'Münster',
|
|
265
|
-
],
|
|
266
|
-
regions: [
|
|
267
|
-
'Bayern',
|
|
268
|
-
'Nordrhein-Westfalen',
|
|
269
|
-
'Baden-Württemberg',
|
|
270
|
-
'Niedersachsen',
|
|
271
|
-
'Hessen',
|
|
272
|
-
'Sachsen',
|
|
273
|
-
'Rheinland-Pfalz',
|
|
274
|
-
'Berlin',
|
|
275
|
-
'Schleswig-Holstein',
|
|
276
|
-
'Brandenburg',
|
|
277
|
-
'Sachsen-Anhalt',
|
|
278
|
-
'Thüringen',
|
|
279
|
-
'Hamburg',
|
|
280
|
-
'Mecklenburg-Vorpommern',
|
|
281
|
-
'Bremen',
|
|
282
|
-
'Saarland',
|
|
283
|
-
],
|
|
284
|
-
zipFormat: () => String(randomNumber(10000, 99999)).padStart(5, '0'),
|
|
285
|
-
},
|
|
286
|
-
es: {
|
|
287
|
-
name: 'Spain',
|
|
288
|
-
streetTypes: [
|
|
289
|
-
'Calle',
|
|
290
|
-
'Avenida',
|
|
291
|
-
'Plaza',
|
|
292
|
-
'Paseo',
|
|
293
|
-
'Rambla',
|
|
294
|
-
'Carretera',
|
|
295
|
-
'Camino',
|
|
296
|
-
'Vía',
|
|
297
|
-
'Travesía',
|
|
298
|
-
'Callejón',
|
|
299
|
-
],
|
|
300
|
-
streetNames: [
|
|
301
|
-
'Mayor',
|
|
302
|
-
'Real',
|
|
303
|
-
'Nueva',
|
|
304
|
-
'del Sol',
|
|
305
|
-
'de la Luna',
|
|
306
|
-
'del Rey',
|
|
307
|
-
'de la Reina',
|
|
308
|
-
'del Mar',
|
|
309
|
-
'de la Paz',
|
|
310
|
-
'de la Victoria',
|
|
311
|
-
'Cervantes',
|
|
312
|
-
'Goya',
|
|
313
|
-
'Velázquez',
|
|
314
|
-
'Picasso',
|
|
315
|
-
'Dalí',
|
|
316
|
-
'de España',
|
|
317
|
-
'de Colón',
|
|
318
|
-
'de la Constitución',
|
|
319
|
-
'del Prado',
|
|
320
|
-
'de las Flores',
|
|
321
|
-
],
|
|
322
|
-
cities: [
|
|
323
|
-
'Madrid',
|
|
324
|
-
'Barcelona',
|
|
325
|
-
'Valencia',
|
|
326
|
-
'Seville',
|
|
327
|
-
'Zaragoza',
|
|
328
|
-
'Málaga',
|
|
329
|
-
'Murcia',
|
|
330
|
-
'Palma',
|
|
331
|
-
'Las Palmas',
|
|
332
|
-
'Bilbao',
|
|
333
|
-
'Alicante',
|
|
334
|
-
'Córdoba',
|
|
335
|
-
'Valladolid',
|
|
336
|
-
'Vigo',
|
|
337
|
-
'Gijón',
|
|
338
|
-
'Hospitalet',
|
|
339
|
-
'A Coruña',
|
|
340
|
-
'Granada',
|
|
341
|
-
'Vitoria',
|
|
342
|
-
'Elche',
|
|
343
|
-
],
|
|
344
|
-
regions: [
|
|
345
|
-
'Andalucía',
|
|
346
|
-
'Cataluña',
|
|
347
|
-
'Madrid',
|
|
348
|
-
'Comunidad Valenciana',
|
|
349
|
-
'Galicia',
|
|
350
|
-
'Castilla y León',
|
|
351
|
-
'País Vasco',
|
|
352
|
-
'Castilla-La Mancha',
|
|
353
|
-
'Canarias',
|
|
354
|
-
'Murcia',
|
|
355
|
-
'Aragón',
|
|
356
|
-
'Extremadura',
|
|
357
|
-
'Asturias',
|
|
358
|
-
'Navarra',
|
|
359
|
-
'Cantabria',
|
|
360
|
-
'La Rioja',
|
|
361
|
-
'Baleares',
|
|
362
|
-
],
|
|
363
|
-
zipFormat: () => String(randomNumber(10000, 52999)).padStart(5, '0'),
|
|
364
|
-
},
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
const COUNTRY_KEYS = Object.keys(countries);
|
|
368
|
-
|
|
369
|
-
export interface Address {
|
|
370
|
-
street: string;
|
|
371
|
-
city: string;
|
|
372
|
-
zip: string;
|
|
373
|
-
state: string;
|
|
374
|
-
country: string;
|
|
375
|
-
countryCode: string;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
export interface AddressResult {
|
|
379
|
-
addresses: Address[];
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Generates one or more fictional postal addresses for a given country.
|
|
384
|
-
*
|
|
385
|
-
* @param countryCode - Country code: "fr", "us", "uk", "de", or "es" (random if omitted)
|
|
386
|
-
* @param count - Number of addresses to generate (1–10)
|
|
387
|
-
* @returns Array of addresses with street, city, zip, state, country, and countryCode
|
|
388
|
-
* @throws Error if the country code is invalid or count is out of range
|
|
389
|
-
*/
|
|
390
|
-
export default function address(countryCode?: string, count: number = 1): AddressResult {
|
|
391
|
-
if (count < 1 || count > MAX_ADDRESS_COUNT) {
|
|
392
|
-
throw new Error(`Count must be between 1 and ${MAX_ADDRESS_COUNT}`);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const code = (countryCode ?? random(COUNTRY_KEYS)).toLowerCase();
|
|
396
|
-
if (!countries[code]) {
|
|
397
|
-
throw new Error(`Unknown country code "${code}". Supported: ${COUNTRY_KEYS.join(', ')}`);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const data = countries[code]!;
|
|
401
|
-
|
|
402
|
-
const addresses: Address[] = Array.from({ length: count }, () => ({
|
|
403
|
-
street: `${randomNumber(1, 200)} ${random(data.streetTypes)} ${random(data.streetNames)}`,
|
|
404
|
-
city: random(data.cities),
|
|
405
|
-
zip: data.zipFormat(),
|
|
406
|
-
state: random(data.regions),
|
|
407
|
-
country: data.name,
|
|
408
|
-
countryCode: code.toUpperCase(),
|
|
409
|
-
}));
|
|
410
|
-
|
|
411
|
-
return { addresses };
|
|
412
|
-
}
|
package/src/modules/v4/agent.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { MAX_STRING_LENGTH } from '../../constants.js';
|
|
2
|
-
|
|
3
|
-
export interface UserAgentResult {
|
|
4
|
-
raw: string;
|
|
5
|
-
browser: { name: string; version: string; major: string };
|
|
6
|
-
os: { name: string; version: string };
|
|
7
|
-
device: { type: 'mobile' | 'tablet' | 'desktop'; vendor: string };
|
|
8
|
-
engine: { name: string; version: string };
|
|
9
|
-
bot: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const WINDOWS_MAP: Record<string, string> = {
|
|
13
|
-
'10.0': 'Windows 10/11',
|
|
14
|
-
'6.3': 'Windows 8.1',
|
|
15
|
-
'6.2': 'Windows 8',
|
|
16
|
-
'6.1': 'Windows 7',
|
|
17
|
-
'6.0': 'Windows Vista',
|
|
18
|
-
'5.1': 'Windows XP',
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Parses a User-Agent string and extracts browser, OS, device, engine
|
|
23
|
-
* and bot information.
|
|
24
|
-
*
|
|
25
|
-
* @param ua - The User-Agent string to parse
|
|
26
|
-
* @returns Structured breakdown of the User-Agent
|
|
27
|
-
* @throws Error if the User-Agent string is missing or too long
|
|
28
|
-
*/
|
|
29
|
-
export default function agent(ua: string): UserAgentResult {
|
|
30
|
-
if (!ua || typeof ua !== 'string') throw new Error('A User-Agent string is required');
|
|
31
|
-
if (ua.length > MAX_STRING_LENGTH) throw new Error(`User-Agent must be less than ${MAX_STRING_LENGTH} characters`);
|
|
32
|
-
|
|
33
|
-
const unknown = { name: 'unknown', version: 'unknown', major: 'unknown' };
|
|
34
|
-
|
|
35
|
-
const bot = /bot|crawl|spider|lighthouse|headless|prerender|slurp|bingpreview/i.test(ua);
|
|
36
|
-
|
|
37
|
-
// Browser — order matters: Edge/Opera before Chrome
|
|
38
|
-
let browser = { ...unknown };
|
|
39
|
-
const browserRules: [RegExp, string][] = [
|
|
40
|
-
[/Edg\/(\d+[\d.]*)/i, 'Edge'],
|
|
41
|
-
[/OPR\/(\d+[\d.]*)/i, 'Opera'],
|
|
42
|
-
[/SamsungBrowser\/(\d+[\d.]*)/i, 'Samsung Internet'],
|
|
43
|
-
[/Chrome\/(\d+[\d.]*)/i, 'Chrome'],
|
|
44
|
-
[/Firefox\/(\d+[\d.]*)/i, 'Firefox'],
|
|
45
|
-
[/Version\/([\d.]+).*Safari/i, 'Safari'],
|
|
46
|
-
[/MSIE ([\d.]+)/i, 'Internet Explorer'],
|
|
47
|
-
[/Trident\/.*rv:([\d.]+)/i, 'Internet Explorer'],
|
|
48
|
-
];
|
|
49
|
-
for (const [re, name] of browserRules) {
|
|
50
|
-
const m = ua.match(re);
|
|
51
|
-
if (m) {
|
|
52
|
-
browser = { name, version: m[1]!, major: m[1]!.split('.')[0]! };
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// OS
|
|
58
|
-
let os = { name: 'unknown', version: 'unknown' };
|
|
59
|
-
const osRules: [RegExp, (m: RegExpMatchArray) => typeof os][] = [
|
|
60
|
-
[/iPhone OS ([\d_]+)/i, (m) => ({ name: 'iOS', version: m[1]!.replace(/_/g, '.') })],
|
|
61
|
-
[/iPad.*OS ([\d_]+)/i, (m) => ({ name: 'iPadOS', version: m[1]!.replace(/_/g, '.') })],
|
|
62
|
-
[/Android ([\d.]+)/i, (m) => ({ name: 'Android', version: m[1]! })],
|
|
63
|
-
[/Windows NT ([\d.]+)/i, (m) => ({ name: WINDOWS_MAP[m[1]!] ?? 'Windows', version: m[1]! })],
|
|
64
|
-
[/Mac OS X ([\d_.]+)/i, (m) => ({ name: 'macOS', version: m[1]!.replace(/_/g, '.') })],
|
|
65
|
-
[/Linux/i, () => ({ name: 'Linux', version: 'unknown' })],
|
|
66
|
-
];
|
|
67
|
-
for (const [re, build] of osRules) {
|
|
68
|
-
const m = ua.match(re);
|
|
69
|
-
if (m) {
|
|
70
|
-
os = build(m);
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Device
|
|
76
|
-
const isMobile = /Mobi|Android|iPhone|iPod/i.test(ua) && !/iPad/i.test(ua);
|
|
77
|
-
const isTablet = /iPad/i.test(ua) || (/Android/i.test(ua) && !/Mobile/i.test(ua));
|
|
78
|
-
const deviceType: 'mobile' | 'tablet' | 'desktop' = isMobile ? 'mobile' : isTablet ? 'tablet' : 'desktop';
|
|
79
|
-
|
|
80
|
-
let vendor = 'unknown';
|
|
81
|
-
if (/iPhone|iPad|Macintosh/i.test(ua)) vendor = 'Apple';
|
|
82
|
-
else if (/Samsung/i.test(ua)) vendor = 'Samsung';
|
|
83
|
-
else if (/Pixel|Nexus/i.test(ua)) vendor = 'Google';
|
|
84
|
-
else if (/Huawei/i.test(ua)) vendor = 'Huawei';
|
|
85
|
-
|
|
86
|
-
// Engine
|
|
87
|
-
let engine = { name: 'unknown', version: 'unknown' };
|
|
88
|
-
const engineRules: [RegExp, string][] = [
|
|
89
|
-
[/AppleWebKit\/([\d.]+)/i, 'WebKit'],
|
|
90
|
-
[/Gecko\/([\d.]+)/i, 'Gecko'],
|
|
91
|
-
[/Trident\/([\d.]+)/i, 'Trident'],
|
|
92
|
-
];
|
|
93
|
-
for (const [re, name] of engineRules) {
|
|
94
|
-
const m = ua.match(re);
|
|
95
|
-
if (m) {
|
|
96
|
-
// Chrome and Edge use Blink, a WebKit fork
|
|
97
|
-
const engineName = name === 'WebKit' && /Chrome|Edg/i.test(ua) ? 'Blink' : name;
|
|
98
|
-
engine = { name: engineName, version: m[1]! };
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return { raw: ua, browser, os, device: { type: deviceType, vendor }, engine, bot };
|
|
104
|
-
}
|