@mikkelscheike/email-provider-links 1.0.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/dist/index.js ADDED
@@ -0,0 +1,516 @@
1
+ "use strict";
2
+ /**
3
+ * Email Provider Links
4
+ *
5
+ * A TypeScript package that provides direct links to email providers
6
+ * based on email addresses to streamline login and password reset flows.
7
+ *
8
+ * The package uses a two-tier detection system:
9
+ * 1. Fast domain lookup against a JSON database of known providers
10
+ * 2. DNS-based detection for custom business domains using MX/TXT record analysis
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.isValidEmail = isValidEmail;
16
+ exports.extractDomain = extractDomain;
17
+ exports.findEmailProvider = findEmailProvider;
18
+ exports.getEmailProviderLink = getEmailProviderLink;
19
+ exports.getSupportedProviders = getSupportedProviders;
20
+ exports.isEmailProviderSupported = isEmailProviderSupported;
21
+ exports.detectProviderByDNS = detectProviderByDNS;
22
+ exports.getEmailProviderLinkWithDNS = getEmailProviderLinkWithDNS;
23
+ const fs_1 = require("fs");
24
+ const path_1 = require("path");
25
+ const util_1 = require("util");
26
+ const dns_1 = require("dns");
27
+ // Convert Node.js callback-style DNS functions to Promise-based
28
+ const resolveMxAsync = (0, util_1.promisify)(dns_1.resolveMx);
29
+ const resolveTxtAsync = (0, util_1.promisify)(dns_1.resolveTxt);
30
+ /**
31
+ * Default timeout for DNS queries in milliseconds.
32
+ */
33
+ const DEFAULT_DNS_TIMEOUT = 5000; // 5 seconds
34
+ /**
35
+ * Creates a Promise that rejects after the specified timeout.
36
+ *
37
+ * @param ms - Timeout in milliseconds
38
+ * @returns Promise that rejects with timeout error
39
+ * @internal
40
+ */
41
+ function createTimeout(ms) {
42
+ return new Promise((_, reject) => {
43
+ setTimeout(() => reject(new Error(`DNS query timeout after ${ms}ms`)), ms);
44
+ });
45
+ }
46
+ /**
47
+ * Wraps a DNS query with a timeout.
48
+ *
49
+ * @param promise - The DNS query promise
50
+ * @param timeoutMs - Timeout in milliseconds
51
+ * @returns Promise that resolves with DNS result or rejects on timeout
52
+ * @internal
53
+ */
54
+ function withTimeout(promise, timeoutMs) {
55
+ return Promise.race([promise, createTimeout(timeoutMs)]);
56
+ }
57
+ // Load providers from external JSON file
58
+ let EMAIL_PROVIDERS = [];
59
+ // Performance optimization: Create a domain-to-provider Map for O(1) lookups
60
+ let DOMAIN_TO_PROVIDER_MAP = new Map();
61
+ /**
62
+ * Builds a Map for fast domain-to-provider lookups.
63
+ * This optimization improves lookup performance from O(n*m) to O(1)
64
+ * where n = number of providers, m = average domains per provider.
65
+ *
66
+ * @internal
67
+ */
68
+ function buildDomainMap() {
69
+ DOMAIN_TO_PROVIDER_MAP.clear();
70
+ for (const provider of EMAIL_PROVIDERS) {
71
+ for (const domain of provider.domains) {
72
+ DOMAIN_TO_PROVIDER_MAP.set(domain.toLowerCase(), provider);
73
+ }
74
+ }
75
+ }
76
+ try {
77
+ const providersPath = (0, path_1.join)(__dirname, '..', 'providers', 'emailproviders.json');
78
+ const providersData = JSON.parse((0, fs_1.readFileSync)(providersPath, 'utf8'));
79
+ EMAIL_PROVIDERS = providersData.providers;
80
+ buildDomainMap(); // Build optimized lookup map
81
+ }
82
+ catch (error) {
83
+ // Fallback to hardcoded providers if JSON file is not found
84
+ console.warn('Could not load providers from JSON file, using fallback providers');
85
+ EMAIL_PROVIDERS = [
86
+ {
87
+ companyProvider: 'Google',
88
+ loginUrl: 'https://accounts.google.com/signin',
89
+ domains: ['gmail.com', 'googlemail.com']
90
+ },
91
+ {
92
+ companyProvider: 'Microsoft',
93
+ loginUrl: 'https://outlook.live.com/owa/',
94
+ domains: ['outlook.com', 'hotmail.com', 'live.com', 'msn.com']
95
+ },
96
+ {
97
+ companyProvider: 'Yahoo',
98
+ loginUrl: 'https://login.yahoo.com/',
99
+ domains: ['yahoo.com', 'yahoo.co.uk', 'yahoo.ca', 'yahoo.com.au', 'ymail.com', 'rocketmail.com']
100
+ }
101
+ ];
102
+ buildDomainMap(); // Build optimized lookup map for fallback too
103
+ }
104
+ /**
105
+ * Validates if a string is a valid email address using a basic regex pattern.
106
+ *
107
+ * @param email - The string to validate as an email address
108
+ * @returns true if the string matches basic email format, false otherwise
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * isValidEmail('user@gmail.com'); // true
113
+ * isValidEmail('invalid-email'); // false
114
+ * isValidEmail('user@domain'); // false
115
+ * ```
116
+ *
117
+ * @remarks
118
+ * This uses a simple regex pattern that covers most common email formats.
119
+ * It may not catch all edge cases defined in RFC 5322, but works for
120
+ * standard email addresses.
121
+ */
122
+ function isValidEmail(email) {
123
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
124
+ return emailRegex.test(email);
125
+ }
126
+ /**
127
+ * Extracts the domain portion from an email address.
128
+ *
129
+ * @param email - The email address to extract the domain from
130
+ * @returns The domain in lowercase, or null if the email is invalid
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * extractDomain('user@Gmail.com'); // 'gmail.com'
135
+ * extractDomain('test@yahoo.co.uk'); // 'yahoo.co.uk'
136
+ * extractDomain('invalid-email'); // null
137
+ * ```
138
+ *
139
+ * @remarks
140
+ * The domain is automatically normalized to lowercase for consistent matching.
141
+ */
142
+ function extractDomain(email) {
143
+ if (!isValidEmail(email)) {
144
+ return null;
145
+ }
146
+ const parts = email.split('@');
147
+ return parts.length === 2 ? parts[1].toLowerCase() : null;
148
+ }
149
+ /**
150
+ * Finds an email provider by matching the domain against the known providers database.
151
+ * Uses an optimized Map for O(1) lookup performance.
152
+ *
153
+ * @param domain - The email domain to look up (e.g., 'gmail.com')
154
+ * @returns The matching EmailProvider object, or null if not found
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const provider = findEmailProvider('gmail.com');
159
+ * console.log(provider?.companyProvider); // 'Gmail'
160
+ * console.log(provider?.loginUrl); // 'https://mail.google.com/mail/'
161
+ * ```
162
+ *
163
+ * @remarks
164
+ * This function performs a case-insensitive O(1) lookup using a pre-built Map.
165
+ * It only checks the predefined JSON database, not DNS records.
166
+ * Performance optimized from O(n*m) to O(1) where n=providers, m=domains per provider.
167
+ */
168
+ function findEmailProvider(domain) {
169
+ const normalizedDomain = domain.toLowerCase();
170
+ return DOMAIN_TO_PROVIDER_MAP.get(normalizedDomain) || null;
171
+ }
172
+ /**
173
+ * Gets email provider information and login URL for a given email address.
174
+ * This is the basic/synchronous version that only checks predefined domains.
175
+ *
176
+ * @param email - The email address to analyze
177
+ * @returns EmailProviderResult containing provider info and login URL
178
+ *
179
+ * @example
180
+ * ```typescript
181
+ * const result = getEmailProviderLink('user@gmail.com');
182
+ * console.log(result.loginUrl); // 'https://mail.google.com/mail/'
183
+ * console.log(result.provider?.companyProvider); // 'Gmail'
184
+ * ```
185
+ *
186
+ * @remarks
187
+ * This function only checks against the predefined JSON database of known domains.
188
+ * It will NOT detect business domains that use major email providers (e.g.,
189
+ * mycompany.com using Google Workspace). For comprehensive detection including
190
+ * business domains, use {@link getEmailProviderLinkWithDNS} instead.
191
+ *
192
+ * **Limitations:**
193
+ * - Only synchronous operation (no DNS lookups)
194
+ * - Limited to domains in the JSON database
195
+ * - Won't detect custom business domains
196
+ * - No proxy service detection
197
+ */
198
+ function getEmailProviderLink(email) {
199
+ const domain = extractDomain(email);
200
+ if (!domain) {
201
+ return {
202
+ provider: null,
203
+ email,
204
+ loginUrl: null
205
+ };
206
+ }
207
+ const provider = findEmailProvider(domain);
208
+ return {
209
+ provider,
210
+ email,
211
+ loginUrl: provider ? provider.loginUrl : null
212
+ };
213
+ }
214
+ /**
215
+ * Returns an array of all supported email providers.
216
+ *
217
+ * @returns A copy of the EMAIL_PROVIDERS array
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * const providers = getSupportedProviders();
222
+ * console.log(providers.length); // 55+
223
+ * console.log(providers[0].companyProvider); // 'Gmail'
224
+ * ```
225
+ *
226
+ * @remarks
227
+ * Returns a shallow copy to prevent external modification of the internal
228
+ * providers array. The returned array includes both consumer email providers
229
+ * (gmail.com, yahoo.com) and business email providers with DNS detection patterns.
230
+ */
231
+ function getSupportedProviders() {
232
+ return [...EMAIL_PROVIDERS];
233
+ }
234
+ /**
235
+ * Checks if an email address uses a supported email provider.
236
+ *
237
+ * @param email - The email address to check
238
+ * @returns true if the provider is supported, false otherwise
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * isEmailProviderSupported('user@gmail.com'); // true
243
+ * isEmailProviderSupported('user@unknown.com'); // false
244
+ * ```
245
+ *
246
+ * @remarks
247
+ * This is a convenience function that uses {@link getEmailProviderLink} internally.
248
+ * It only checks predefined domains, not DNS-based detection. For business
249
+ * domain support checking, you would need to use {@link getEmailProviderLinkWithDNS}.
250
+ */
251
+ function isEmailProviderSupported(email) {
252
+ const result = getEmailProviderLink(email);
253
+ return result.provider !== null;
254
+ }
255
+ /**
256
+ * Detects proxy services that obscure the actual email provider by analyzing MX records.
257
+ *
258
+ * @param mxRecords - Array of MX records from DNS lookup
259
+ * @returns The name of the detected proxy service, or null if none detected
260
+ *
261
+ * @internal
262
+ * @remarks
263
+ * This function checks MX record patterns against known proxy/CDN services.
264
+ * When a proxy is detected, it means we cannot determine the actual email
265
+ * provider behind the proxy service. Currently detects:
266
+ * - Cloudflare Email Routing
267
+ * - CloudFront (AWS)
268
+ * - Fastly
269
+ * - MaxCDN
270
+ * - KeyCDN
271
+ * - Mailgun proxy configurations
272
+ * - SendGrid proxy configurations
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * const mxRecords = [{ exchange: 'isaac.mx.cloudflare.net', priority: 10 }];
277
+ * const proxy = detectProxyService(mxRecords);
278
+ * console.log(proxy); // 'Cloudflare'
279
+ * ```
280
+ */
281
+ function detectProxyService(mxRecords) {
282
+ const proxyPatterns = [
283
+ { service: 'Cloudflare', patterns: ['mxrecord.io', 'mxrecord.mx', 'cloudflare'] },
284
+ { service: 'CloudFront', patterns: ['cloudfront.net'] },
285
+ { service: 'Fastly', patterns: ['fastly.com'] },
286
+ { service: 'MaxCDN', patterns: ['maxcdn.com'] },
287
+ { service: 'KeyCDN', patterns: ['keycdn.com'] },
288
+ { service: 'Mailgun Proxy', patterns: ['mailgun.org', 'mg.', 'mailgun'] },
289
+ { service: 'SendGrid Proxy', patterns: ['sendgrid.net', 'sendgrid.com'] }
290
+ ];
291
+ for (const mxRecord of mxRecords) {
292
+ const exchange = mxRecord.exchange.toLowerCase();
293
+ for (const proxyService of proxyPatterns) {
294
+ for (const pattern of proxyService.patterns) {
295
+ if (exchange.includes(pattern.toLowerCase())) {
296
+ return proxyService.service;
297
+ }
298
+ }
299
+ }
300
+ }
301
+ return null;
302
+ }
303
+ /**
304
+ * Performs DNS-based detection for custom business domains using MX and TXT record analysis.
305
+ * This function is used internally by {@link getEmailProviderLinkWithDNS} but can also be
306
+ * called directly to analyze domain email configuration.
307
+ *
308
+ * @param domain - The domain to analyze (e.g., 'mycompany.com')
309
+ * @param timeoutMs - Optional timeout for DNS queries in milliseconds (default: 5000ms)
310
+ * @returns Promise resolving to DNSDetectionResult with provider info or proxy detection
311
+ *
312
+ * @example
313
+ * ```typescript
314
+ * const result = await detectProviderByDNS('microsoft.com');
315
+ * console.log(result.provider?.companyProvider); // 'Microsoft 365 (Business)'
316
+ * console.log(result.detectionMethod); // 'mx_record'
317
+ * ```
318
+ *
319
+ * @remarks
320
+ * **Detection Algorithm:**
321
+ * 1. Performs MX record lookup for the domain
322
+ * 2. Checks if MX records match known proxy services (Cloudflare, etc.)
323
+ * 3. If proxy detected, returns null provider with proxy info
324
+ * 4. Otherwise, matches MX records against business email provider patterns
325
+ * 5. If no MX match, falls back to TXT record analysis (SPF records, etc.)
326
+ * 6. Returns the first matching provider or null if none found
327
+ *
328
+ * **Provider Patterns Checked:**
329
+ * - Google Workspace: aspmx.l.google.com, aspmx2.googlemail.com, etc.
330
+ * - Microsoft 365: *.protection.outlook.com, *.outlook.com
331
+ * - ProtonMail: mail.protonmail.ch, mailsec.protonmail.ch
332
+ * - FastMail: *.messagingengine.com
333
+ * - And many others...
334
+ *
335
+ * **Error Handling:**
336
+ * DNS lookup failures are caught and the function gracefully falls back
337
+ * to the next detection method or returns null if all methods fail.
338
+ */
339
+ async function detectProviderByDNS(domain, timeoutMs = DEFAULT_DNS_TIMEOUT) {
340
+ const normalizedDomain = domain.toLowerCase();
341
+ // Get providers that support custom domain detection
342
+ const customDomainProviders = EMAIL_PROVIDERS.filter(provider => provider.customDomainDetection &&
343
+ (provider.customDomainDetection.mxPatterns || provider.customDomainDetection.txtPatterns));
344
+ // Try MX record detection first with timeout
345
+ try {
346
+ const mxRecords = await withTimeout(resolveMxAsync(normalizedDomain), timeoutMs);
347
+ // Check for proxy services first
348
+ const proxyService = detectProxyService(mxRecords);
349
+ if (proxyService) {
350
+ return {
351
+ provider: null,
352
+ detectionMethod: 'proxy_detected',
353
+ proxyService
354
+ };
355
+ }
356
+ for (const provider of customDomainProviders) {
357
+ if (provider.customDomainDetection?.mxPatterns) {
358
+ for (const mxRecord of mxRecords) {
359
+ const exchange = mxRecord.exchange.toLowerCase();
360
+ for (const pattern of provider.customDomainDetection.mxPatterns) {
361
+ if (exchange.includes(pattern.toLowerCase())) {
362
+ return {
363
+ provider,
364
+ detectionMethod: 'mx_record'
365
+ };
366
+ }
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ catch (error) {
373
+ // MX lookup failed, continue to TXT records
374
+ }
375
+ // Try TXT record detection with timeout
376
+ try {
377
+ const txtRecords = await withTimeout(resolveTxtAsync(normalizedDomain), timeoutMs);
378
+ const flatTxtRecords = txtRecords.flat();
379
+ for (const provider of customDomainProviders) {
380
+ if (provider.customDomainDetection?.txtPatterns) {
381
+ for (const txtRecord of flatTxtRecords) {
382
+ const record = txtRecord.toLowerCase();
383
+ for (const pattern of provider.customDomainDetection.txtPatterns) {
384
+ if (record.includes(pattern.toLowerCase())) {
385
+ return {
386
+ provider,
387
+ detectionMethod: 'txt_record'
388
+ };
389
+ }
390
+ }
391
+ }
392
+ }
393
+ }
394
+ }
395
+ catch (error) {
396
+ // TXT lookup failed
397
+ }
398
+ return {
399
+ provider: null,
400
+ detectionMethod: null
401
+ };
402
+ }
403
+ /**
404
+ * Enhanced email provider detection with automatic DNS-based custom domain detection.
405
+ * This is the recommended function for most use cases as it provides comprehensive
406
+ * detection coverage including business domains and proxy services.
407
+ *
408
+ * @param email - The email address to analyze
409
+ * @param timeoutMs - Optional timeout for DNS queries in milliseconds (default: 5000ms)
410
+ * @returns Promise resolving to EmailProviderResult with provider info and detection method
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * // Consumer email (fast domain match)
415
+ * const gmail = await getEmailProviderLinkWithDNS('user@gmail.com');
416
+ * console.log(gmail.provider?.companyProvider); // 'Gmail'
417
+ * console.log(gmail.detectionMethod); // 'domain_match'
418
+ *
419
+ * // Business domain (DNS detection)
420
+ * const business = await getEmailProviderLinkWithDNS('user@mycompany.com');
421
+ * console.log(business.provider?.companyProvider); // 'Google Workspace' (if detected)
422
+ * console.log(business.detectionMethod); // 'mx_record'
423
+ *
424
+ * // Proxied domain (proxy detection)
425
+ * const proxied = await getEmailProviderLinkWithDNS('user@proxied-domain.com');
426
+ * console.log(proxied.provider); // null
427
+ * console.log(proxied.proxyService); // 'Cloudflare'
428
+ * console.log(proxied.detectionMethod); // 'proxy_detected'
429
+ * ```
430
+ *
431
+ * @remarks
432
+ * **Detection Hierarchy (in order):**
433
+ * 1. **Domain Match**: Fast lookup against predefined domains (gmail.com, yahoo.com, etc.)
434
+ * 2. **DNS MX Records**: Analyzes mail exchange records for business email providers
435
+ * 3. **DNS TXT Records**: Checks SPF and verification records as fallback
436
+ * 4. **Proxy Detection**: Identifies when domains are behind CDN/proxy services
437
+ *
438
+ * **Supported Detection Cases:**
439
+ * - ✅ Consumer emails: gmail.com, yahoo.com, outlook.com, etc.
440
+ * - ✅ Business domains: Google Workspace, Microsoft 365, ProtonMail Business, etc.
441
+ * - ✅ Proxy services: Cloudflare, CloudFront, Fastly, etc.
442
+ * - ✅ International providers: QQ Mail, NetEase, Yandex, etc.
443
+ *
444
+ * **Performance:**
445
+ * - Fast for known consumer domains (synchronous JSON lookup)
446
+ * - Additional DNS lookup time for unknown domains (~100-500ms)
447
+ * - Graceful degradation if DNS lookups fail
448
+ *
449
+ * **Error Handling:**
450
+ * - Invalid email addresses return null provider
451
+ * - DNS lookup failures are caught and don't throw errors
452
+ * - Network timeouts gracefully fall back to null detection
453
+ *
454
+ * **Use Cases:**
455
+ * - Password reset flows ("Check your Gmail inbox")
456
+ * - Login form enhancements (direct links to email providers)
457
+ * - Email client detection for support purposes
458
+ * - Business domain analysis for enterprise features
459
+ */
460
+ async function getEmailProviderLinkWithDNS(email, timeoutMs = DEFAULT_DNS_TIMEOUT) {
461
+ const domain = extractDomain(email);
462
+ if (!domain) {
463
+ return {
464
+ provider: null,
465
+ email,
466
+ loginUrl: null
467
+ };
468
+ }
469
+ // First try standard domain matching
470
+ const provider = findEmailProvider(domain);
471
+ if (provider) {
472
+ return {
473
+ provider,
474
+ email,
475
+ loginUrl: provider.loginUrl,
476
+ detectionMethod: 'domain_match'
477
+ };
478
+ }
479
+ // If no direct match, try DNS-based detection for custom domains
480
+ const dnsResult = await detectProviderByDNS(domain, timeoutMs);
481
+ if (dnsResult.provider) {
482
+ return {
483
+ provider: dnsResult.provider,
484
+ email,
485
+ loginUrl: dnsResult.provider.loginUrl,
486
+ detectionMethod: dnsResult.detectionMethod || 'mx_record'
487
+ };
488
+ }
489
+ // Handle proxy detection case
490
+ if (dnsResult.detectionMethod === 'proxy_detected') {
491
+ return {
492
+ provider: null,
493
+ email,
494
+ loginUrl: null,
495
+ detectionMethod: 'proxy_detected',
496
+ proxyService: dnsResult.proxyService
497
+ };
498
+ }
499
+ return {
500
+ provider: null,
501
+ email,
502
+ loginUrl: null
503
+ };
504
+ }
505
+ // Default export for convenience
506
+ exports.default = {
507
+ getEmailProviderLink,
508
+ getEmailProviderLinkWithDNS,
509
+ detectProviderByDNS,
510
+ isValidEmail,
511
+ extractDomain,
512
+ findEmailProvider,
513
+ getSupportedProviders,
514
+ isEmailProviderSupported
515
+ };
516
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@mikkelscheike/email-provider-links",
3
+ "version": "1.0.0",
4
+ "description": "A TypeScript package that provides direct links to email providers based on email addresses to streamline login and password reset flows",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*",
9
+ "providers/**/*"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "jest",
14
+ "test:watch": "jest --watch",
15
+ "test:coverage": "jest --coverage",
16
+ "prepublishOnly": "npm run build",
17
+ "dev": "tsx src/index.ts"
18
+ },
19
+ "keywords": [
20
+ "email",
21
+ "provider",
22
+ "login",
23
+ "password-reset",
24
+ "gmail",
25
+ "outlook",
26
+ "yahoo",
27
+ "typescript",
28
+ "npm",
29
+ "utility"
30
+ ],
31
+ "author": "Mikkel Scheike",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/mikkelscheike/email-provider-links.git"
36
+ },
37
+ "homepage": "https://github.com/mikkelscheike/email-provider-links#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/mikkelscheike/email-provider-links/issues"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "packageManager": "pnpm@10.11.1",
45
+ "devDependencies": {
46
+ "@semantic-release/commit-analyzer": "^13.0.1",
47
+ "@semantic-release/github": "^11.0.3",
48
+ "@semantic-release/npm": "^12.0.1",
49
+ "@semantic-release/release-notes-generator": "^14.0.3",
50
+ "@types/jest": "^30.0.0",
51
+ "@types/node": "^24.0.3",
52
+ "conventional-changelog-conventionalcommits": "^9.0.0",
53
+ "jest": "^30.0.1",
54
+ "semantic-release": "^24.2.5",
55
+ "ts-jest": "^29.4.0",
56
+ "tsx": "^4.20.3",
57
+ "typescript": "^5.8.3"
58
+ }
59
+ }