veripy-sdk 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/LICENSE.md ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026, Veripy
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # veripy-sdk
2
+
3
+ The official Node.js wrapper for the Veripy Email Verification API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install veripy-sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import VeripyClient from 'veripy-sdk';
15
+
16
+ const client = new VeripyClient({
17
+ apiKey: 'vp_your_api_key_here'
18
+ });
19
+
20
+ async function run() {
21
+ const result = await client.verify('test@example.com');
22
+ console.log(result);
23
+ /**
24
+ * {
25
+ * valid: true,
26
+ * email: "test@example.com",
27
+ * results: {
28
+ * syntax: true,
29
+ * disposable: false,
30
+ * mx_records: true,
31
+ * mailbox: true
32
+ * },
33
+ * score: 0.95,
34
+ * timestamp: 1741512345678
35
+ * }
36
+ */
37
+ }
38
+
39
+ run();
40
+ ```
@@ -0,0 +1,50 @@
1
+ interface VerifyResult {
2
+ valid: boolean;
3
+ email: string;
4
+ results: {
5
+ syntax: boolean;
6
+ disposable: boolean;
7
+ mx_records: boolean;
8
+ mailbox: boolean;
9
+ };
10
+ score: number;
11
+ timestamp: number;
12
+ }
13
+ export interface VeripyConfig {
14
+ spamDetection?: boolean;
15
+ rateLimit?: boolean;
16
+ }
17
+ export declare class VeripyClient {
18
+ private url;
19
+ private apiKey;
20
+ private globalConfig;
21
+ private history;
22
+ private readonly SPAM_WINDOW_MS;
23
+ private readonly MAX_SIMILAR_REQUESTS;
24
+ constructor(options: {
25
+ url?: string;
26
+ apiKey: string;
27
+ config?: VeripyConfig;
28
+ });
29
+ /**
30
+ * Helper to detect if two emails are highly similar variations
31
+ * (e.g., test1@example.com and test2@example.com)
32
+ */
33
+ private isSimilar;
34
+ /**
35
+ * Helper for built in rate limiter (Token Bucket)
36
+ */
37
+ private tokens;
38
+ private lastRefill;
39
+ private readonly MAX_TOKENS;
40
+ private readonly REFILL_RATE_PER_MS;
41
+ private checkRateLimit;
42
+ /**
43
+ * Verifies an email address.
44
+ * @param email The email address to verify.
45
+ * @param config Optional configuration to override global settings.
46
+ * @returns A Promise resolving to the verification result.
47
+ */
48
+ verify(email: string, config?: VeripyConfig): Promise<VerifyResult>;
49
+ }
50
+ export default VeripyClient;
package/dist/index.js ADDED
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VeripyClient = void 0;
4
+ class VeripyClient {
5
+ url;
6
+ apiKey;
7
+ globalConfig;
8
+ // Local memory cache for spam detection
9
+ history = [];
10
+ SPAM_WINDOW_MS = 60000; // 1 minute window
11
+ MAX_SIMILAR_REQUESTS = 3; // Block after 3 similar variations
12
+ constructor(options) {
13
+ this.url =
14
+ options.url || "https://lovable-alpaca-951.eu-west-1.convex.site";
15
+ if (!options.apiKey) {
16
+ throw new Error("VeripyClient requires an apiKey.");
17
+ }
18
+ this.apiKey = options.apiKey;
19
+ this.globalConfig = {
20
+ spamDetection: options.config?.spamDetection ?? true,
21
+ rateLimit: options.config?.rateLimit ?? true,
22
+ };
23
+ }
24
+ /**
25
+ * Helper to detect if two emails are highly similar variations
26
+ * (e.g., test1@example.com and test2@example.com)
27
+ */
28
+ isSimilar(email1, email2) {
29
+ const [local1, domain1] = email1.toLowerCase().split("@");
30
+ const [local2, domain2] = email2.toLowerCase().split("@");
31
+ if (domain1 !== domain2)
32
+ return false;
33
+ // Strip trailing numbers from the local part (e.g. 'test12' -> 'test')
34
+ const base1 = local1.replace(/\d+$/, "");
35
+ const base2 = local2.replace(/\d+$/, "");
36
+ // Also catch "plus addressing" variations (e.g. user+1@gmail.com and user+2@gmail.com)
37
+ const plusBase1 = local1.split("+")[0];
38
+ const plusBase2 = local2.split("+")[0];
39
+ return base1 === base2 || plusBase1 === plusBase2;
40
+ }
41
+ /**
42
+ * Helper for built in rate limiter (Token Bucket)
43
+ */
44
+ tokens = 10; // default starting burst
45
+ lastRefill = Date.now();
46
+ MAX_TOKENS = 10;
47
+ REFILL_RATE_PER_MS = 10 / (60 * 1000); // 10 tokens per minute
48
+ checkRateLimit() {
49
+ const now = Date.now();
50
+ const timePassed = now - this.lastRefill;
51
+ // Refill tokens based on time passed
52
+ this.tokens = Math.min(this.MAX_TOKENS, this.tokens + timePassed * this.REFILL_RATE_PER_MS);
53
+ this.lastRefill = now;
54
+ if (this.tokens < 1) {
55
+ throw new Error("Veripy Error: Rate limit exceeded locally. Slow down your requests.");
56
+ }
57
+ this.tokens -= 1;
58
+ }
59
+ /**
60
+ * Verifies an email address.
61
+ * @param email The email address to verify.
62
+ * @param config Optional configuration to override global settings.
63
+ * @returns A Promise resolving to the verification result.
64
+ */
65
+ async verify(email, config) {
66
+ if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
67
+ throw new Error("Veripy Error: Invalid email format provided to SDK.");
68
+ }
69
+ const activeConfig = { ...this.globalConfig, ...config };
70
+ const now = Date.now();
71
+ // 1. Local Rate Limiting
72
+ if (activeConfig.rateLimit) {
73
+ this.checkRateLimit();
74
+ }
75
+ // 2. Local Spam Detection
76
+ if (activeConfig.spamDetection) {
77
+ // Clean up history older than our window
78
+ this.history = this.history.filter((req) => now - req.timestamp < this.SPAM_WINDOW_MS);
79
+ // Check for spam behavior locally
80
+ const similarCount = this.history.filter((req) => this.isSimilar(req.email, email)).length;
81
+ if (similarCount >= this.MAX_SIMILAR_REQUESTS) {
82
+ throw new Error("Veripy Error: Spam behavior detected. Too many highly similar requests locally.");
83
+ }
84
+ // Add to local history
85
+ this.history.push({ email, timestamp: now });
86
+ }
87
+ const response = await fetch(`${this.url}/v1/verify`, {
88
+ method: "POST",
89
+ headers: {
90
+ "Content-Type": "application/json",
91
+ "x-api-key": this.apiKey,
92
+ },
93
+ body: JSON.stringify({ email }),
94
+ });
95
+ if (!response.ok) {
96
+ const error = await response
97
+ .json()
98
+ .catch(() => ({ error: response.statusText }));
99
+ throw new Error(`Veripy API Error: ${response.status} - ${error.error || response.statusText}`);
100
+ }
101
+ return (await response.json());
102
+ }
103
+ }
104
+ exports.VeripyClient = VeripyClient;
105
+ exports.default = VeripyClient;
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "veripy-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Email verification wrapper for Veripy",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "vitest run",
10
+ "test:watch": "vitest"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "keywords": [
16
+ "verification",
17
+ "email",
18
+ "veripy",
19
+ "spam"
20
+ ],
21
+ "author": "Richard Banguiz",
22
+ "license": "ISC",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/your-org/veripy.git",
26
+ "directory": "sdk"
27
+ },
28
+ "homepage": "https://github.com/your-org/veripy/tree/main/sdk#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/your-org/veripy/issues"
31
+ },
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ }
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.0.0",
40
+ "typescript": "^5.0.0",
41
+ "vitest": "^4.1.0"
42
+ }
43
+ }