Skip to content

Commit ee99133

Browse files
authored
Merge pull request #5 from rguarascia/feat/external-provider
Add external sources feature.
2 parents c057ab2 + ae592bb commit ee99133

File tree

4 files changed

+136
-23
lines changed

4 files changed

+136
-23
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/node_modules
2+
/test/*.js
3+
pnpm-lock.yaml

index.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
1212
return (mod && mod.__esModule) ? mod : { "default": mod };
1313
};
1414
Object.defineProperty(exports, "__esModule", { value: true });
15+
exports.ExternalSourceError = void 0;
1516
exports.default = disposableEmailDetector;
1617
const promises_1 = __importDefault(require("fs/promises"));
1718
const path_1 = __importDefault(require("path"));
@@ -24,12 +25,43 @@ const loadDomains = () => __awaiter(void 0, void 0, void 0, function* () {
2425
cachedDomains = disposableDomains;
2526
return disposableDomains;
2627
});
28+
class ExternalSourceError extends Error {
29+
constructor(message = 'URL must be provided when loading from external source') {
30+
super(message);
31+
this.name = 'ExternalSourceError';
32+
Object.setPrototypeOf(this, ExternalSourceError.prototype);
33+
}
34+
}
35+
exports.ExternalSourceError = ExternalSourceError;
36+
const loadDomainsFromExternalSource = (_a) => __awaiter(void 0, [_a], void 0, function* ({ github, url }) {
37+
if (cachedDomains)
38+
return cachedDomains;
39+
const URL = github ? "https://raw.githubusercontent.com/IntegerAlex/disposable-email-detector/refs/heads/main/index.json" : url;
40+
if (!URL)
41+
throw new ExternalSourceError();
42+
console.info(`Loading disposable domains from ${URL}`);
43+
try {
44+
const response = yield fetch(URL);
45+
const disposableDomains = yield response.json();
46+
cachedDomains = disposableDomains;
47+
return disposableDomains;
48+
}
49+
catch (error) {
50+
throw new ExternalSourceError("Failed to load disposable domains from the provided URL");
51+
}
52+
});
2753
// Function to detect disposable email addresses
28-
function disposableEmailDetector(email) {
54+
function disposableEmailDetector(email, options) {
2955
return __awaiter(this, void 0, void 0, function* () {
3056
try {
31-
// Load the list of disposable email domains from the index.json file
32-
const disposableDomains = yield loadDomains();
57+
let disposableDomains = [];
58+
// Load from external source
59+
if (options === null || options === void 0 ? void 0 : options.loadFromSource) {
60+
disposableDomains = yield loadDomainsFromExternalSource(options.loadFromSource);
61+
}
62+
else {
63+
disposableDomains = yield loadDomains();
64+
}
3365
// Extract the domain from the email address
3466
const domain = email.split('@')[1].toLowerCase(); // Get the domain part of the email address and convert it to lowercase
3567
// Check if the domain is in the list of disposable domains
@@ -42,6 +74,9 @@ function disposableEmailDetector(email) {
4274
else if (error instanceof SyntaxError) {
4375
console.error('Invalid JSON format in index.json. Please correct the file.');
4476
}
77+
else if (error instanceof ExternalSourceError) {
78+
console.error(error.message);
79+
}
4580
else {
4681
console.error('Unexpected error:', error);
4782
}

index.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,48 @@ const loadDomains = async () => {
1111
return disposableDomains;
1212
}
1313

14+
export class ExternalSourceError extends Error {
15+
constructor(message: string = 'URL must be provided when loading from external source') {
16+
super(message);
17+
this.name = 'ExternalSourceError';
18+
Object.setPrototypeOf(this, ExternalSourceError.prototype);
19+
}
20+
}
21+
22+
const loadDomainsFromExternalSource = async ({github, url}: LoadFromSource) => {
23+
if (cachedDomains) return cachedDomains;
24+
const URL = github ? "https://raw.githubusercontent.com/IntegerAlex/disposable-email-detector/refs/heads/main/index.json" : url;
25+
if (!URL) throw new ExternalSourceError();
26+
try {
27+
const response = await fetch(URL);
28+
const disposableDomains = await response.json();
29+
cachedDomains = disposableDomains
30+
return disposableDomains;
31+
} catch (error) {
32+
throw new ExternalSourceError("Failed to load disposable domains from the provided URL");
33+
}
34+
}
35+
36+
type LoadFromSource = {
37+
github?: boolean;
38+
url?: string;
39+
}
40+
41+
type Options = {
42+
loadFromSource?: LoadFromSource;
43+
}
44+
1445
// Function to detect disposable email addresses
15-
export default async function disposableEmailDetector(email: string): Promise<boolean> {
46+
export default async function disposableEmailDetector(email: string, options?: Options): Promise<boolean> {
1647
try {
17-
// Load the list of disposable email domains from the index.json file
18-
const disposableDomains = await loadDomains();
48+
let disposableDomains = [];
49+
// Load from external source
50+
if (options?.loadFromSource) {
51+
disposableDomains = await loadDomainsFromExternalSource(options.loadFromSource);
52+
} else {
53+
disposableDomains = await loadDomains();
54+
}
55+
1956

2057
// Extract the domain from the email address
2158
const domain = email.split('@')[1].toLowerCase(); // Get the domain part of the email address and convert it to lowercase
@@ -28,7 +65,10 @@ export default async function disposableEmailDetector(email: string): Promise<bo
2865
console.error('index.json not found. Please create it with disposable domains.');
2966
} else if (error instanceof SyntaxError) {
3067
console.error('Invalid JSON format in index.json. Please correct the file.');
31-
} else {
68+
} else if (error instanceof ExternalSourceError) {
69+
console.error(error.message);
70+
}
71+
else {
3272
console.error('Unexpected error:', error);
3373
}
3474
return false;

test/usage.ts

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,67 @@
1-
import fs from 'fs/promises';
2-
import disposableEmailDetector from "../index"
3-
import path from 'path';
1+
import fs from "fs/promises";
2+
import disposableEmailDetector from "../index";
3+
import path from "path";
44

55
// Load test emails from file
6-
const filePath: string = path.join(__dirname, './testEmails.txt');
6+
const filePath: string = path.join(__dirname, "./testEmails.txt");
77

88
async function loadTestEmails(filePath: string): Promise<string[]> {
9-
const rawData = await fs.readFile(filePath);
10-
return rawData.toString().trim().split('\n');
9+
const rawData = await fs.readFile(filePath);
10+
return rawData.toString().trim().split("\n");
1111
}
1212

1313
async function runTests() {
1414
try {
15-
const testEmails = await loadTestEmails(filePath);
15+
const testEmails = await loadTestEmails(filePath);
1616

17-
for (const email of testEmails) {
18-
const isDisposable = await disposableEmailDetector(email);
19-
console.log(email, '- Disposable:', isDisposable);
20-
}
21-
console.log('Test passed.');
17+
for (const email of testEmails) {
18+
const isDisposable = await disposableEmailDetector(email);
19+
console.log(email, "- Disposable:", isDisposable);
20+
}
21+
console.log("Test passed.");
22+
} catch (error: any) {
23+
console.error("Unexpected error:", error);
24+
console.error("Please check the file path and try again.");
25+
console.error("Test failed.");
26+
}
2227
}
23-
catch (error: any) {
24-
console.error('Unexpected error:', error);
25-
console.error('Please check the file path and try again.');
26-
console.error('Test failed.');
28+
29+
async function runTestsExternalGithub() {
30+
try {
31+
const testEmails = await loadTestEmails(filePath);
32+
33+
for (const email of testEmails) {
34+
const isDisposable = await disposableEmailDetector(email, {
35+
loadFromSource: { github: true },
36+
});
37+
console.log(email, "- Disposable:", isDisposable);
38+
}
39+
console.log("External: Github Test passed.");
40+
} catch (error: any) {
41+
console.error("Unexpected error:", error);
42+
console.error("Please check the github repository for index.json and try again.");
43+
console.error("Test failed.");
44+
}
2745
}
2846

47+
async function runTestsExternalURL() {
48+
try {
49+
const testEmails = await loadTestEmails(filePath);
2950

51+
for (const email of testEmails) {
52+
const isDisposable = await disposableEmailDetector(email, {
53+
loadFromSource: { url: "https://pastebin.com/raw/HL70DeZg" },
54+
});
55+
console.log(email, "- Disposable:", isDisposable);
56+
}
57+
console.log("External: URL Test passed.");
58+
} catch (error: any) {
59+
console.error("Unexpected error:", error);
60+
console.error("Please check the URL and try again.");
61+
console.error("Test failed.");
62+
}
3063
}
3164

3265
runTests();
66+
runTestsExternalGithub();
67+
runTestsExternalURL();

0 commit comments

Comments
 (0)