@emailcheck/email-validator-js 2.11.0 → 2.13.1-beta.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 +290 -25
- package/dist/adapters/lru-adapter.d.ts +19 -0
- package/dist/adapters/redis-adapter.d.ts +45 -0
- package/dist/cache-factory.d.ts +39 -0
- package/dist/cache-interface.d.ts +124 -0
- package/dist/cache.d.ts +28 -0
- package/dist/dns.d.ts +2 -1
- package/dist/domain-suggester.d.ts +6 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.js +216 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +216 -78
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/validator.d.ts +2 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
- [API Reference](#api-reference)
|
|
21
21
|
- [Configuration](#configuration-options)
|
|
22
22
|
- [Examples](#examples)
|
|
23
|
+
- [Custom Cache Injection](#-custom-cache-injection)
|
|
23
24
|
- [Performance & Caching](#-performance--caching)
|
|
24
25
|
- [Email Provider Databases](#️-email-provider-databases)
|
|
25
26
|
- [Testing](#testing)
|
|
@@ -122,7 +123,7 @@ import { verifyEmail } from '@emailcheck/email-validator-js';
|
|
|
122
123
|
|
|
123
124
|
// Basic usage
|
|
124
125
|
const result = await verifyEmail({
|
|
125
|
-
emailAddress: 'user@
|
|
126
|
+
emailAddress: 'user@mydomain.com',
|
|
126
127
|
verifyMx: true,
|
|
127
128
|
verifySmtp: true,
|
|
128
129
|
timeout: 3000
|
|
@@ -237,7 +238,7 @@ Verify multiple emails in parallel with concurrency control.
|
|
|
237
238
|
Detect first and last name from email address.
|
|
238
239
|
|
|
239
240
|
```typescript
|
|
240
|
-
const name = detectName('john.doe@
|
|
241
|
+
const name = detectName('john.doe@mydomain.com');
|
|
241
242
|
// Returns: { firstName: 'John', lastName: 'Doe', confidence: 0.9 }
|
|
242
243
|
```
|
|
243
244
|
|
|
@@ -270,7 +271,7 @@ const customMethod = (email: string) => {
|
|
|
270
271
|
};
|
|
271
272
|
|
|
272
273
|
const name = detectNameFromEmail({
|
|
273
|
-
email: 'user@
|
|
274
|
+
email: 'user@mydomain.com',
|
|
274
275
|
customMethod: customMethod
|
|
275
276
|
});
|
|
276
277
|
```
|
|
@@ -349,10 +350,10 @@ getDomainSimilarity('gmail.com', 'yahoo.com'); // 0.3
|
|
|
349
350
|
Get domain age information via WHOIS lookup.
|
|
350
351
|
|
|
351
352
|
```typescript
|
|
352
|
-
const ageInfo = await getDomainAge('
|
|
353
|
+
const ageInfo = await getDomainAge('mydomain.com');
|
|
353
354
|
// Returns:
|
|
354
355
|
// {
|
|
355
|
-
// domain: '
|
|
356
|
+
// domain: 'mydomain.com',
|
|
356
357
|
// creationDate: Date,
|
|
357
358
|
// ageInDays: 7890,
|
|
358
359
|
// ageInYears: 21.6,
|
|
@@ -361,8 +362,8 @@ const ageInfo = await getDomainAge('example.com');
|
|
|
361
362
|
// }
|
|
362
363
|
|
|
363
364
|
// Works with email addresses and URLs too
|
|
364
|
-
await getDomainAge('user@
|
|
365
|
-
await getDomainAge('https://
|
|
365
|
+
await getDomainAge('user@mydomain.com');
|
|
366
|
+
await getDomainAge('https://mydomain.com/path');
|
|
366
367
|
```
|
|
367
368
|
|
|
368
369
|
**Parameters:**
|
|
@@ -375,15 +376,15 @@ await getDomainAge('https://example.com/path');
|
|
|
375
376
|
Get detailed domain registration status via WHOIS.
|
|
376
377
|
|
|
377
378
|
```typescript
|
|
378
|
-
const status = await getDomainRegistrationStatus('
|
|
379
|
+
const status = await getDomainRegistrationStatus('mydomain.com');
|
|
379
380
|
// Returns:
|
|
380
381
|
// {
|
|
381
|
-
// domain: '
|
|
382
|
+
// domain: 'mydomain.com',
|
|
382
383
|
// isRegistered: true,
|
|
383
384
|
// isAvailable: false,
|
|
384
385
|
// status: ['clientTransferProhibited'],
|
|
385
386
|
// registrar: 'Example Registrar',
|
|
386
|
-
// nameServers: ['ns1.
|
|
387
|
+
// nameServers: ['ns1.mydomain.com', 'ns2.mydomain.com'],
|
|
387
388
|
// expirationDate: Date,
|
|
388
389
|
// isExpired: false,
|
|
389
390
|
// daysUntilExpiration: 365,
|
|
@@ -430,7 +431,7 @@ isFreeEmail('corporate.com'); // false
|
|
|
430
431
|
Validate email format (RFC 5321 compliant).
|
|
431
432
|
|
|
432
433
|
```typescript
|
|
433
|
-
isValidEmail('user@
|
|
434
|
+
isValidEmail('user@mydomain.com'); // true
|
|
434
435
|
isValidEmail('invalid.email'); // false
|
|
435
436
|
```
|
|
436
437
|
|
|
@@ -446,7 +447,7 @@ isValidEmail('invalid.email'); // false
|
|
|
446
447
|
Validate if a domain has a valid TLD.
|
|
447
448
|
|
|
448
449
|
```typescript
|
|
449
|
-
isValidEmailDomain('
|
|
450
|
+
isValidEmailDomain('mydomain.com'); // true
|
|
450
451
|
isValidEmailDomain('example.invalid'); // false
|
|
451
452
|
```
|
|
452
453
|
|
|
@@ -623,7 +624,7 @@ const result = await verifyEmailDetailed({
|
|
|
623
624
|
```typescript
|
|
624
625
|
import { verifyEmailBatch } from '@emailcheck/email-validator-js';
|
|
625
626
|
|
|
626
|
-
const emails = ['user1@gmail.com', 'user2@
|
|
627
|
+
const emails = ['user1@gmail.com', 'user2@mydomain.com', 'invalid@fake.com'];
|
|
627
628
|
|
|
628
629
|
const result = await verifyEmailBatch({
|
|
629
630
|
emailAddresses: emails,
|
|
@@ -641,23 +642,23 @@ const result = await verifyEmailBatch({
|
|
|
641
642
|
import { detectName, verifyEmailDetailed } from '@emailcheck/email-validator-js';
|
|
642
643
|
|
|
643
644
|
// Standalone name detection - now with composite name support
|
|
644
|
-
const name = detectName('john.doe@
|
|
645
|
+
const name = detectName('john.doe@mydomain.com');
|
|
645
646
|
// name: { firstName: 'John', lastName: 'Doe', confidence: 0.9 }
|
|
646
647
|
|
|
647
648
|
// Handle alphanumeric composite names
|
|
648
|
-
const composite = detectName('mo1.test2@
|
|
649
|
+
const composite = detectName('mo1.test2@mydomain.com');
|
|
649
650
|
// composite: { firstName: 'Mo1', lastName: 'Test2', confidence: 0.6 }
|
|
650
651
|
|
|
651
652
|
// Smart handling of numbers and suffixes
|
|
652
|
-
const withNumbers = detectName('john.doe123@
|
|
653
|
+
const withNumbers = detectName('john.doe123@mydomain.com');
|
|
653
654
|
// withNumbers: { firstName: 'John', lastName: 'Doe', confidence: 0.8 }
|
|
654
655
|
|
|
655
|
-
const withSuffix = detectName('jane.smith.dev@
|
|
656
|
+
const withSuffix = detectName('jane.smith.dev@mydomain.com');
|
|
656
657
|
// withSuffix: { firstName: 'Jane', lastName: 'Smith', confidence: 0.7 }
|
|
657
658
|
|
|
658
659
|
// Integrated with email verification
|
|
659
660
|
const result = await verifyEmailDetailed({
|
|
660
|
-
emailAddress: 'jane_smith@
|
|
661
|
+
emailAddress: 'jane_smith@mydomain.com',
|
|
661
662
|
detectName: true
|
|
662
663
|
});
|
|
663
664
|
// result.detectedName: { firstName: 'Jane', lastName: 'Smith', confidence: 0.8 }
|
|
@@ -669,7 +670,7 @@ const customMethod = (email: string) => {
|
|
|
669
670
|
};
|
|
670
671
|
|
|
671
672
|
const resultCustom = await verifyEmail({
|
|
672
|
-
emailAddress: 'user@
|
|
673
|
+
emailAddress: 'user@mydomain.com',
|
|
673
674
|
detectName: true,
|
|
674
675
|
nameDetectionMethod: customMethod
|
|
675
676
|
});
|
|
@@ -776,16 +777,16 @@ for (const [email, result] of batch.results) {
|
|
|
776
777
|
|
|
777
778
|
```typescript
|
|
778
779
|
// First verification - hits DNS and SMTP
|
|
779
|
-
const first = await verifyEmail({
|
|
780
|
-
emailAddress: 'cached@
|
|
781
|
-
verifyMx: true
|
|
780
|
+
const first = await verifyEmail({
|
|
781
|
+
emailAddress: 'cached@mydomain.com',
|
|
782
|
+
verifyMx: true
|
|
782
783
|
});
|
|
783
784
|
// Takes ~500ms
|
|
784
785
|
|
|
785
786
|
// Second verification - uses cache
|
|
786
|
-
const second = await verifyEmail({
|
|
787
|
-
emailAddress: 'cached@
|
|
788
|
-
verifyMx: true
|
|
787
|
+
const second = await verifyEmail({
|
|
788
|
+
emailAddress: 'cached@mydomain.com',
|
|
789
|
+
verifyMx: true
|
|
789
790
|
});
|
|
790
791
|
// Takes ~1ms (cached)
|
|
791
792
|
|
|
@@ -793,6 +794,270 @@ const second = await verifyEmail({
|
|
|
793
794
|
clearAllCaches();
|
|
794
795
|
```
|
|
795
796
|
|
|
797
|
+
## 🚀 Custom Cache Injection
|
|
798
|
+
|
|
799
|
+
The library supports parameter-based cache injection, allowing you to use custom cache backends like Redis, Memcached, or any LRU-compatible cache implementation.
|
|
800
|
+
|
|
801
|
+
### Built-in Cache Adapters
|
|
802
|
+
|
|
803
|
+
#### LRU Cache (Default)
|
|
804
|
+
```typescript
|
|
805
|
+
import { CacheFactory } from '@emailcheck/email-validator-js';
|
|
806
|
+
|
|
807
|
+
// Create LRU cache with custom settings
|
|
808
|
+
const lruCache = CacheFactory.createLRUCache({
|
|
809
|
+
mx: 1800000, // 30 minutes for MX records
|
|
810
|
+
disposable: 86400000, // 24 hours for disposable checks
|
|
811
|
+
free: 86400000, // 24 hours for free email checks
|
|
812
|
+
smtp: 1800000, // 30 minutes for SMTP verification
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
// Use with email verification
|
|
816
|
+
const result = await verifyEmail({
|
|
817
|
+
emailAddress: 'user@mydomain.com',
|
|
818
|
+
verifyMx: true,
|
|
819
|
+
verifySmtp: true,
|
|
820
|
+
cache: lruCache // Pass the cache instance
|
|
821
|
+
});
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
#### Redis Cache
|
|
825
|
+
```typescript
|
|
826
|
+
import { CacheFactory } from '@emailcheck/email-validator-js';
|
|
827
|
+
import Redis from 'ioredis';
|
|
828
|
+
|
|
829
|
+
// Create Redis client
|
|
830
|
+
const redis = new Redis({
|
|
831
|
+
host: 'localhost',
|
|
832
|
+
port: 6379,
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
// Create Redis cache adapter
|
|
836
|
+
const redisCache = CacheFactory.createRedisCache(redis, {
|
|
837
|
+
keyPrefix: 'email_validator:',
|
|
838
|
+
defaultTtlMs: 3600000, // 1 hour default TTL
|
|
839
|
+
jsonSerializer: {
|
|
840
|
+
stringify: (value) => JSON.stringify(value),
|
|
841
|
+
parse: (value) => JSON.parse(value)
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// Use with batch verification
|
|
846
|
+
const batchResult = await verifyEmailBatch({
|
|
847
|
+
emailAddresses: ['user1@mydomain.com', 'user2@mydomain.com'],
|
|
848
|
+
verifyMx: true,
|
|
849
|
+
verifySmtp: true,
|
|
850
|
+
cache: redisCache,
|
|
851
|
+
concurrency: 10
|
|
852
|
+
});
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
### Custom Cache Implementation
|
|
856
|
+
|
|
857
|
+
Create your own cache adapter by implementing the `ICacheStore` interface:
|
|
858
|
+
|
|
859
|
+
```typescript
|
|
860
|
+
import { CacheFactory, type ICacheStore } from '@emailcheck/email-validator-js';
|
|
861
|
+
|
|
862
|
+
class MyCustomCache<T> implements ICacheStore<T> {
|
|
863
|
+
private store = new Map<string, { value: T; expiry: number }>();
|
|
864
|
+
|
|
865
|
+
async get(key: string): Promise<T | null> {
|
|
866
|
+
const item = this.store.get(key);
|
|
867
|
+
if (!item) return null;
|
|
868
|
+
|
|
869
|
+
if (Date.now() > item.expiry) {
|
|
870
|
+
this.store.delete(key);
|
|
871
|
+
return null;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
return item.value;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
async set(key: string, value: T, ttlMs?: number): Promise<void> {
|
|
878
|
+
const expiry = Date.now() + (ttlMs || 3600000);
|
|
879
|
+
this.store.set(key, { value, expiry });
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
async delete(key: string): Promise<boolean> {
|
|
883
|
+
return this.store.delete(key);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
async has(key: string): Promise<boolean> {
|
|
887
|
+
return this.store.has(key);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
async clear(): Promise<void> {
|
|
891
|
+
this.store.clear();
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
size(): number {
|
|
895
|
+
return this.store.size;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Create custom cache
|
|
900
|
+
const customCache = CacheFactory.createCustomCache(
|
|
901
|
+
(cacheType, defaultTtl, defaultSize) => new MyCustomCache(),
|
|
902
|
+
{
|
|
903
|
+
mx: 1800000,
|
|
904
|
+
disposable: 86400000,
|
|
905
|
+
free: 86400000
|
|
906
|
+
}
|
|
907
|
+
);
|
|
908
|
+
|
|
909
|
+
// Use with verification
|
|
910
|
+
const result = await verifyEmailDetailed({
|
|
911
|
+
emailAddress: 'user@mydomain.com',
|
|
912
|
+
verifyMx: true,
|
|
913
|
+
verifySmtp: true,
|
|
914
|
+
checkDisposable: true,
|
|
915
|
+
cache: customCache
|
|
916
|
+
});
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
### Mixed Cache Configuration
|
|
920
|
+
|
|
921
|
+
Use different cache backends for different types of data:
|
|
922
|
+
|
|
923
|
+
```typescript
|
|
924
|
+
const mixedCache = CacheFactory.createMixedCache({
|
|
925
|
+
// Use Redis for frequently accessed data
|
|
926
|
+
mx: {
|
|
927
|
+
store: redisStore, // Your Redis store implementation
|
|
928
|
+
ttlMs: 1800000
|
|
929
|
+
},
|
|
930
|
+
smtp: {
|
|
931
|
+
store: redisStore,
|
|
932
|
+
ttlMs: 900000
|
|
933
|
+
},
|
|
934
|
+
|
|
935
|
+
// Use LRU for less critical data
|
|
936
|
+
disposable: {
|
|
937
|
+
ttlMs: 86400000 // 24 hours
|
|
938
|
+
},
|
|
939
|
+
free: {
|
|
940
|
+
ttlMs: 86400000 // 24 hours
|
|
941
|
+
},
|
|
942
|
+
domainValid: {
|
|
943
|
+
ttlMs: 86400000 // 24 hours
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// Verification will use appropriate cache for each operation
|
|
948
|
+
await verifyEmail({
|
|
949
|
+
emailAddress: 'user@tempmail.com',
|
|
950
|
+
verifyMx: true,
|
|
951
|
+
verifySmtp: true,
|
|
952
|
+
checkDisposable: true,
|
|
953
|
+
checkFree: true,
|
|
954
|
+
cache: mixedCache
|
|
955
|
+
});
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
### Cache Best Practices
|
|
959
|
+
|
|
960
|
+
1. **Choose Appropriate TTL**:
|
|
961
|
+
- MX Records: 30-60 minutes (DNS changes infrequently)
|
|
962
|
+
- SMTP Results: 15-30 minutes (Mailbox status changes)
|
|
963
|
+
- Disposable/Free Lists: 12-24 hours (Provider lists update slowly)
|
|
964
|
+
|
|
965
|
+
2. **Handle Cache Errors Gracefully**:
|
|
966
|
+
```typescript
|
|
967
|
+
const result = await verifyEmail({
|
|
968
|
+
emailAddress: 'user@mydomain.com',
|
|
969
|
+
cache: unreliableCache, // Cache might fail
|
|
970
|
+
verifyMx: true,
|
|
971
|
+
verifySmtp: true
|
|
972
|
+
});
|
|
973
|
+
// Library continues to work even if cache operations fail
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
3. **Monitor Cache Hit Rates**:
|
|
977
|
+
```typescript
|
|
978
|
+
import { CacheFactory } from '@emailcheck/email-validator-js';
|
|
979
|
+
|
|
980
|
+
// Create cache with hit tracking
|
|
981
|
+
const cache = CacheFactory.createLRUCache();
|
|
982
|
+
let hits = 0;
|
|
983
|
+
let misses = 0;
|
|
984
|
+
|
|
985
|
+
// Wrap cache store to track metrics
|
|
986
|
+
const trackingCache = {
|
|
987
|
+
get: async (key: string) => {
|
|
988
|
+
const result = await cache.mx.get(key);
|
|
989
|
+
if (result !== null && result !== undefined) {
|
|
990
|
+
hits++;
|
|
991
|
+
} else {
|
|
992
|
+
misses++;
|
|
993
|
+
}
|
|
994
|
+
return result;
|
|
995
|
+
},
|
|
996
|
+
set: cache.mx.set.bind(cache.mx),
|
|
997
|
+
delete: cache.mx.delete.bind(cache.mx),
|
|
998
|
+
has: cache.mx.has.bind(cache.mx),
|
|
999
|
+
clear: cache.mx.clear.bind(cache.mx),
|
|
1000
|
+
size: () => cache.mx.size()
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
// Monitor performance
|
|
1004
|
+
console.log(`Cache hit rate: ${(hits / (hits + misses) * 100).toFixed(1)}%`);
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
### Cache Key Structure
|
|
1008
|
+
|
|
1009
|
+
The library uses the following cache key patterns:
|
|
1010
|
+
|
|
1011
|
+
- **MX Records**: Domain name (e.g., `mydomain.com`)
|
|
1012
|
+
- **SMTP Verification**: Full email with `:smtp` suffix (e.g., `user@mydomain.com:smtp`)
|
|
1013
|
+
- **Disposable Check**: Domain name (e.g., `tempmail.com`)
|
|
1014
|
+
- **Free Provider Check**: Domain name (e.g., `gmail.com`)
|
|
1015
|
+
- **Domain Validation**: Domain name (e.g., `mydomain.com`)
|
|
1016
|
+
|
|
1017
|
+
### Redis Production Setup
|
|
1018
|
+
|
|
1019
|
+
For production Redis deployment:
|
|
1020
|
+
|
|
1021
|
+
```typescript
|
|
1022
|
+
import Redis from 'ioredis';
|
|
1023
|
+
import { CacheFactory } from '@emailcheck/email-validator-js';
|
|
1024
|
+
|
|
1025
|
+
// Production Redis configuration
|
|
1026
|
+
const redis = new Redis({
|
|
1027
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
1028
|
+
port: parseInt(process.env.REDIS_PORT || '6379'),
|
|
1029
|
+
password: process.env.REDIS_PASSWORD,
|
|
1030
|
+
db: parseInt(process.env.REDIS_DB || '0'),
|
|
1031
|
+
retryDelayOnFailover: 100,
|
|
1032
|
+
maxRetriesPerRequest: 3,
|
|
1033
|
+
lazyConnect: true,
|
|
1034
|
+
keepAlive: 30000,
|
|
1035
|
+
family: 4,
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
// Handle Redis connection errors
|
|
1039
|
+
redis.on('error', (err) => {
|
|
1040
|
+
console.error('Redis connection error:', err);
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
// Production cache with appropriate settings
|
|
1044
|
+
const productionCache = CacheFactory.createRedisCache(redis, {
|
|
1045
|
+
keyPrefix: 'prod:email:',
|
|
1046
|
+
defaultTtlMs: 3600000,
|
|
1047
|
+
// Configure for high availability
|
|
1048
|
+
jsonSerializer: {
|
|
1049
|
+
stringify: (value: any) => JSON.stringify(value),
|
|
1050
|
+
parse: (value: string) => JSON.parse(value)
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
// Graceful shutdown
|
|
1055
|
+
process.on('SIGTERM', async () => {
|
|
1056
|
+
await redis.quit();
|
|
1057
|
+
process.exit(0);
|
|
1058
|
+
});
|
|
1059
|
+
```
|
|
1060
|
+
|
|
796
1061
|
**Note:** Yahoo, Hotmail, and some providers always return `validSmtp: true` as they don't allow mailbox verification.
|
|
797
1062
|
|
|
798
1063
|
## 🌐 Serverless Deployment
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type LRU } from 'tiny-lru';
|
|
2
|
+
import type { ICacheStore } from '../cache-interface';
|
|
3
|
+
/**
|
|
4
|
+
* Adapter to make tiny-lru compatible with our cache interface
|
|
5
|
+
*/
|
|
6
|
+
export declare class LRUAdapter<T> implements ICacheStore<T> {
|
|
7
|
+
private lru;
|
|
8
|
+
constructor(maxSize?: number, ttlMs?: number);
|
|
9
|
+
get(key: string): T | null | undefined;
|
|
10
|
+
set(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
11
|
+
delete(key: string): Promise<boolean>;
|
|
12
|
+
has(key: string): Promise<boolean>;
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
size(): number;
|
|
15
|
+
/**
|
|
16
|
+
* Get the underlying LRU instance for advanced operations
|
|
17
|
+
*/
|
|
18
|
+
getLRU(): LRU<T>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ICacheStore } from '../cache-interface';
|
|
2
|
+
/**
|
|
3
|
+
* Redis client interface to avoid direct dependency on redis package
|
|
4
|
+
*/
|
|
5
|
+
export interface IRedisClient {
|
|
6
|
+
get(key: string): Promise<string | null>;
|
|
7
|
+
set(key: string, value: string, mode?: string, duration?: number): Promise<string | null>;
|
|
8
|
+
del(key: string): Promise<number>;
|
|
9
|
+
exists(key: string): Promise<number>;
|
|
10
|
+
flushdb(): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Redis adapter for the cache interface
|
|
14
|
+
* Supports JSON serialization for complex objects
|
|
15
|
+
*/
|
|
16
|
+
export declare class RedisAdapter<T> implements ICacheStore<T> {
|
|
17
|
+
private redis;
|
|
18
|
+
private keyPrefix;
|
|
19
|
+
private defaultTtlMs;
|
|
20
|
+
private jsonSerializer;
|
|
21
|
+
constructor(redis: IRedisClient, options?: {
|
|
22
|
+
keyPrefix?: string;
|
|
23
|
+
defaultTtlMs?: number;
|
|
24
|
+
jsonSerializer?: {
|
|
25
|
+
stringify: (value: T) => string;
|
|
26
|
+
parse: (value: string) => T;
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
private getKey;
|
|
30
|
+
/**
|
|
31
|
+
* Recursively process an object to convert Date instances to a serializable format
|
|
32
|
+
*/
|
|
33
|
+
private processDatesForSerialization;
|
|
34
|
+
get(key: string): Promise<T | null>;
|
|
35
|
+
set(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
36
|
+
delete(key: string): Promise<boolean>;
|
|
37
|
+
has(key: string): Promise<boolean>;
|
|
38
|
+
clear(): Promise<void>;
|
|
39
|
+
size(): number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Helper method to delete only keys with the configured prefix
|
|
42
|
+
* Requires Redis SCAN command which might not be available in all Redis clients
|
|
43
|
+
*/
|
|
44
|
+
clearPrefixed(): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type IRedisClient } from './adapters/redis-adapter';
|
|
2
|
+
import type { CacheConfig, ICache, ICacheStore } from './cache-interface';
|
|
3
|
+
import { DEFAULT_CACHE_TTL } from './cache-interface';
|
|
4
|
+
/**
|
|
5
|
+
* Cache factory object to create cache instances with different backends
|
|
6
|
+
*/
|
|
7
|
+
export declare const CacheFactory: {
|
|
8
|
+
/**
|
|
9
|
+
* Create a cache with LRU (tiny-lru) backend
|
|
10
|
+
*/
|
|
11
|
+
createLRUCache(customTtl?: Partial<typeof DEFAULT_CACHE_TTL>): ICache;
|
|
12
|
+
/**
|
|
13
|
+
* Create a cache with Redis backend
|
|
14
|
+
*/
|
|
15
|
+
createRedisCache(redis: IRedisClient, options?: {
|
|
16
|
+
keyPrefix?: string;
|
|
17
|
+
customTtl?: Partial<typeof DEFAULT_CACHE_TTL>;
|
|
18
|
+
jsonSerializer?: {
|
|
19
|
+
stringify: (value: any) => string;
|
|
20
|
+
parse: (value: string) => any;
|
|
21
|
+
};
|
|
22
|
+
}): ICache;
|
|
23
|
+
/**
|
|
24
|
+
* Create a cache with custom backend
|
|
25
|
+
*/
|
|
26
|
+
createCustomCache(storeFactory: (cacheType: keyof typeof DEFAULT_CACHE_TTL, defaultTtl: number, defaultSize: number) => ICacheStore, customTtl?: Partial<typeof DEFAULT_CACHE_TTL>): ICache;
|
|
27
|
+
/**
|
|
28
|
+
* Create a mixed cache with different backends for different cache types
|
|
29
|
+
*/
|
|
30
|
+
createMixedCache(config: {
|
|
31
|
+
mx?: CacheConfig;
|
|
32
|
+
disposable?: CacheConfig;
|
|
33
|
+
free?: CacheConfig;
|
|
34
|
+
domainValid?: CacheConfig;
|
|
35
|
+
smtp?: CacheConfig;
|
|
36
|
+
domainSuggestion?: CacheConfig;
|
|
37
|
+
whois?: CacheConfig;
|
|
38
|
+
}): ICache;
|
|
39
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic cache interface that can be implemented by any cache store
|
|
3
|
+
* including in-memory LRU cache, Redis, Memcached, etc.
|
|
4
|
+
*/
|
|
5
|
+
export interface ICacheStore<T = any> {
|
|
6
|
+
/**
|
|
7
|
+
* Get a value from the cache
|
|
8
|
+
* @param key - The cache key
|
|
9
|
+
* @returns The cached value or null/undefined if not found or expired
|
|
10
|
+
*/
|
|
11
|
+
get(key: string): Promise<T | null | undefined> | T | null | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Set a value in the cache with optional TTL
|
|
14
|
+
* @param key - The cache key
|
|
15
|
+
* @param value - The value to cache
|
|
16
|
+
* @param ttlMs - Optional TTL in milliseconds. If not provided, use default TTL
|
|
17
|
+
*/
|
|
18
|
+
set(key: string, value: T, ttlMs?: number): Promise<void> | void;
|
|
19
|
+
/**
|
|
20
|
+
* Delete a value from the cache
|
|
21
|
+
* @param key - The cache key
|
|
22
|
+
*/
|
|
23
|
+
delete(key: string): Promise<boolean> | boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a key exists in the cache
|
|
26
|
+
* @param key - The cache key
|
|
27
|
+
*/
|
|
28
|
+
has(key: string): Promise<boolean> | boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Clear all values from the cache
|
|
31
|
+
*/
|
|
32
|
+
clear(): Promise<void> | void;
|
|
33
|
+
/**
|
|
34
|
+
* Get the current size of the cache (number of entries)
|
|
35
|
+
* Returns undefined if size is not applicable (e.g., Redis)
|
|
36
|
+
*/
|
|
37
|
+
size?(): number | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Synchronous cache interface for in-memory caches
|
|
41
|
+
*/
|
|
42
|
+
export interface ISyncCacheStore<T = any> {
|
|
43
|
+
/**
|
|
44
|
+
* Get a value from the cache
|
|
45
|
+
* @param key - The cache key
|
|
46
|
+
* @returns The cached value or null/undefined if not found or expired
|
|
47
|
+
*/
|
|
48
|
+
get(key: string): T | null | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Set a value in the cache with optional TTL
|
|
51
|
+
* @param key - The cache key
|
|
52
|
+
* @param value - The value to cache
|
|
53
|
+
* @param ttlMs - Optional TTL in milliseconds. If not provided, use default TTL
|
|
54
|
+
*/
|
|
55
|
+
set(key: string, value: T, ttlMs?: number): void;
|
|
56
|
+
/**
|
|
57
|
+
* Delete a value from the cache
|
|
58
|
+
* @param key - The cache key
|
|
59
|
+
*/
|
|
60
|
+
delete(key: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Check if a key exists in the cache
|
|
63
|
+
* @param key - The cache key
|
|
64
|
+
*/
|
|
65
|
+
has(key: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Clear all values from the cache
|
|
68
|
+
*/
|
|
69
|
+
clear(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Get the current size of the cache (number of entries)
|
|
72
|
+
*/
|
|
73
|
+
size?(): number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Cache configuration for different cache types
|
|
77
|
+
*/
|
|
78
|
+
export interface CacheConfig {
|
|
79
|
+
/** Maximum number of entries (for LRU caches) */
|
|
80
|
+
maxSize?: number;
|
|
81
|
+
/** Default TTL in milliseconds */
|
|
82
|
+
ttlMs?: number;
|
|
83
|
+
/** Custom cache store implementation */
|
|
84
|
+
store?: ICacheStore;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Cache holder interface for typed caches
|
|
88
|
+
*/
|
|
89
|
+
export interface ICache {
|
|
90
|
+
mx: ICacheStore<string[]>;
|
|
91
|
+
disposable: ICacheStore<boolean>;
|
|
92
|
+
free: ICacheStore<boolean>;
|
|
93
|
+
domainValid: ICacheStore<boolean>;
|
|
94
|
+
smtp: ICacheStore<boolean | null>;
|
|
95
|
+
domainSuggestion: ICacheStore<{
|
|
96
|
+
suggested: string;
|
|
97
|
+
confidence: number;
|
|
98
|
+
} | null>;
|
|
99
|
+
whois: ICacheStore<any>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Default TTL values in milliseconds
|
|
103
|
+
*/
|
|
104
|
+
export declare const DEFAULT_CACHE_TTL: {
|
|
105
|
+
mx: number;
|
|
106
|
+
disposable: number;
|
|
107
|
+
free: number;
|
|
108
|
+
domainValid: number;
|
|
109
|
+
smtp: number;
|
|
110
|
+
domainSuggestion: number;
|
|
111
|
+
whois: number;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Default cache sizes
|
|
115
|
+
*/
|
|
116
|
+
export declare const DEFAULT_CACHE_SIZE: {
|
|
117
|
+
mx: number;
|
|
118
|
+
disposable: number;
|
|
119
|
+
free: number;
|
|
120
|
+
domainValid: number;
|
|
121
|
+
smtp: number;
|
|
122
|
+
domainSuggestion: number;
|
|
123
|
+
whois: number;
|
|
124
|
+
};
|
package/dist/cache.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ICache, ICacheStore } from './cache-interface';
|
|
1
2
|
import type { ParsedWhoisResult } from './whois-parser';
|
|
2
3
|
export declare const mxCache: import("tiny-lru").LRU<string[]>;
|
|
3
4
|
export declare const disposableCache: import("tiny-lru").LRU<boolean>;
|
|
@@ -9,4 +10,31 @@ export declare const domainSuggestionCache: import("tiny-lru").LRU<{
|
|
|
9
10
|
confidence: number;
|
|
10
11
|
} | null>;
|
|
11
12
|
export declare const whoisCache: import("tiny-lru").LRU<ParsedWhoisResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Set a global custom cache instance to use instead of the default LRU caches
|
|
15
|
+
*/
|
|
16
|
+
export declare function setCustomCache(cache: ICache): void;
|
|
17
|
+
/**
|
|
18
|
+
* Get the current global custom cache instance
|
|
19
|
+
*/
|
|
20
|
+
export declare function getCustomCache(): ICache | null;
|
|
21
|
+
/**
|
|
22
|
+
* Reset to use default LRU caches
|
|
23
|
+
*/
|
|
24
|
+
export declare function resetToDefaultCache(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Get cache adapter that works with passed cache, global cache, or default LRU
|
|
27
|
+
*/
|
|
28
|
+
export declare function getCacheStore<T>(defaultLru: any, cacheType: keyof ICache, passedCache?: ICache | null): ICacheStore<T>;
|
|
29
|
+
export declare const mxCacheStore: (passedCache?: ICache | null) => ICacheStore<string[]>;
|
|
30
|
+
export declare const disposableCacheStore: (passedCache?: ICache | null) => ICacheStore<boolean>;
|
|
31
|
+
export declare const freeCacheStore: (passedCache?: ICache | null) => ICacheStore<boolean>;
|
|
32
|
+
export declare const domainValidCacheStore: (passedCache?: ICache | null) => ICacheStore<boolean>;
|
|
33
|
+
export declare const smtpCacheStore: (passedCache?: ICache | null) => ICacheStore<boolean | null>;
|
|
34
|
+
export declare const domainSuggestionCacheStore: (passedCache?: ICache | null) => ICacheStore<{
|
|
35
|
+
suggested: string;
|
|
36
|
+
confidence: number;
|
|
37
|
+
} | null>;
|
|
38
|
+
export declare const whoisCacheStore: (passedCache?: ICache | null) => ICacheStore<ParsedWhoisResult>;
|
|
12
39
|
export declare function clearAllCaches(): void;
|
|
40
|
+
export type { ICache, ICacheStore } from './cache-interface';
|
package/dist/dns.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ICache } from './cache-interface';
|
|
2
|
+
export declare function resolveMxRecords(domain: string, cache?: ICache | null): Promise<string[]>;
|