dymo-api 1.2.29 → 1.2.31
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/cjs/branches/private/functions/isValidPhone/index.cjs +8 -0
- package/dist/cjs/dymo-api.cjs +51 -21
- package/dist/cjs/lib/resilience/fallback.cjs +427 -0
- package/dist/cjs/lib/resilience/index.cjs +135 -0
- package/dist/esm/branches/private/functions/isValidPhone/index.js +8 -0
- package/dist/esm/dymo-api.js +51 -21
- package/dist/esm/lib/resilience/fallback.js +423 -0
- package/dist/esm/lib/resilience/index.js +131 -0
- package/dist/types/dymo-api.d.ts +22 -17
- package/dist/types/lib/resilience/fallback.d.ts +26 -0
- package/dist/types/lib/resilience/index.d.ts +13 -0
- package/dist/types/lib/types/data-verifier.d.ts +4 -4
- package/dist/types/lib/types/interfaces.d.ts +15 -0
- package/dist/types/lib/types/primitives.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResilienceManager = void 0;
|
|
4
|
+
class RateLimitManager {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.tracker = {};
|
|
7
|
+
}
|
|
8
|
+
static getInstance() {
|
|
9
|
+
if (!RateLimitManager.instance)
|
|
10
|
+
RateLimitManager.instance = new RateLimitManager();
|
|
11
|
+
return RateLimitManager.instance;
|
|
12
|
+
}
|
|
13
|
+
;
|
|
14
|
+
updateRateLimit(clientId, headers) {
|
|
15
|
+
if (!this.tracker[clientId])
|
|
16
|
+
this.tracker[clientId] = {};
|
|
17
|
+
const limitInfo = this.tracker[clientId];
|
|
18
|
+
if (headers["x-ratelimit-limit-requests"])
|
|
19
|
+
limitInfo.limit = parseInt(headers["x-ratelimit-limit-requests"]);
|
|
20
|
+
if (headers["x-ratelimit-remaining-requests"])
|
|
21
|
+
limitInfo.remaining = parseInt(headers["x-ratelimit-remaining-requests"]);
|
|
22
|
+
if (headers["x-ratelimit-reset-requests"])
|
|
23
|
+
limitInfo.resetTime = headers["x-ratelimit-reset-requests"];
|
|
24
|
+
if (headers["retry-after"])
|
|
25
|
+
limitInfo.retryAfter = parseInt(headers["retry-after"]);
|
|
26
|
+
limitInfo.lastUpdated = Date.now();
|
|
27
|
+
}
|
|
28
|
+
;
|
|
29
|
+
isRateLimited(clientId) {
|
|
30
|
+
const limitInfo = this.tracker[clientId];
|
|
31
|
+
return limitInfo?.remaining !== undefined && limitInfo.remaining <= 0;
|
|
32
|
+
}
|
|
33
|
+
;
|
|
34
|
+
getRetryAfter(clientId) {
|
|
35
|
+
return this.tracker[clientId]?.retryAfter;
|
|
36
|
+
}
|
|
37
|
+
;
|
|
38
|
+
clearExpiredLimits() {
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
Object.keys(this.tracker).forEach(clientId => {
|
|
41
|
+
const limitInfo = this.tracker[clientId];
|
|
42
|
+
if (limitInfo.lastUpdated && (now - limitInfo.lastUpdated) > 300000)
|
|
43
|
+
delete this.tracker[clientId];
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
;
|
|
47
|
+
}
|
|
48
|
+
;
|
|
49
|
+
class ResilienceManager {
|
|
50
|
+
constructor(config = {}, clientId = "default") {
|
|
51
|
+
this.config = {
|
|
52
|
+
fallbackEnabled: config.fallbackEnabled ?? false,
|
|
53
|
+
retryAttempts: Math.max(0, config.retryAttempts ?? 2), // Number of additional retries
|
|
54
|
+
retryDelay: Math.max(0, config.retryDelay ?? 1000)
|
|
55
|
+
};
|
|
56
|
+
this.clientId = clientId;
|
|
57
|
+
this.rateLimitManager = RateLimitManager.getInstance();
|
|
58
|
+
}
|
|
59
|
+
;
|
|
60
|
+
async executeWithResilience(axiosClient, requestConfig, fallbackData) {
|
|
61
|
+
let lastError;
|
|
62
|
+
const totalAttempts = 1 + this.config.retryAttempts; // 1 normal + N retries
|
|
63
|
+
// Clean up expired rate limits periodically
|
|
64
|
+
this.rateLimitManager.clearExpiredLimits();
|
|
65
|
+
// Check if client is currently rate limited
|
|
66
|
+
if (this.rateLimitManager.isRateLimited(this.clientId)) {
|
|
67
|
+
const retryAfter = this.rateLimitManager.getRetryAfter(this.clientId);
|
|
68
|
+
if (retryAfter) {
|
|
69
|
+
console.warn(`[Dymo API] Client ${this.clientId} is rate limited. Waiting ${retryAfter} seconds...`);
|
|
70
|
+
await this.sleep(retryAfter * 1000);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (let attempt = 1; attempt <= totalAttempts; attempt++) {
|
|
74
|
+
try {
|
|
75
|
+
const response = await axiosClient.request(requestConfig);
|
|
76
|
+
// Update rate limit tracking
|
|
77
|
+
this.rateLimitManager.updateRateLimit(this.clientId, response.headers);
|
|
78
|
+
// Check for rate limiting
|
|
79
|
+
if (response.status === 429) {
|
|
80
|
+
const retryAfter = this.rateLimitManager.getRetryAfter(this.clientId);
|
|
81
|
+
if (retryAfter) {
|
|
82
|
+
console.warn(`[Dymo API] Rate limited. Waiting ${retryAfter} seconds (no retries)`);
|
|
83
|
+
await this.sleep(retryAfter * 1000);
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Rate limited (429) - not retrying`);
|
|
86
|
+
}
|
|
87
|
+
return response.data;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
lastError = error;
|
|
91
|
+
let shouldRetry = this.shouldRetry(error);
|
|
92
|
+
const isLastAttempt = attempt === totalAttempts;
|
|
93
|
+
// Don't retry on rate limiting (429)
|
|
94
|
+
if (error.response?.status === 429)
|
|
95
|
+
shouldRetry = false;
|
|
96
|
+
if (!shouldRetry || isLastAttempt) {
|
|
97
|
+
if (this.config.fallbackEnabled && fallbackData) {
|
|
98
|
+
console.warn(`[Dymo API] Request failed after ${attempt} attempts. Using fallback data.`);
|
|
99
|
+
return fallbackData;
|
|
100
|
+
}
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
const delay = this.config.retryDelay * Math.pow(2, attempt - 1);
|
|
104
|
+
console.warn(`[Dymo API] Attempt ${attempt} failed. Retrying in ${delay}ms...`);
|
|
105
|
+
await this.sleep(delay);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
throw lastError;
|
|
109
|
+
}
|
|
110
|
+
;
|
|
111
|
+
shouldRetry(error) {
|
|
112
|
+
const statusCode = error.response?.status;
|
|
113
|
+
const isNetworkError = !error.response && error.code !== "ECONNABORTED";
|
|
114
|
+
const isServerError = statusCode && statusCode >= 500;
|
|
115
|
+
// Retry on: network errors, server errors (5xx)
|
|
116
|
+
// DON'T retry on: rate limiting (429) - handled separately
|
|
117
|
+
// DON'T retry on: client errors (4xx except 429)
|
|
118
|
+
return isNetworkError || isServerError;
|
|
119
|
+
}
|
|
120
|
+
;
|
|
121
|
+
sleep(ms) {
|
|
122
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
123
|
+
}
|
|
124
|
+
;
|
|
125
|
+
getConfig() {
|
|
126
|
+
return { ...this.config };
|
|
127
|
+
}
|
|
128
|
+
;
|
|
129
|
+
getClientId() {
|
|
130
|
+
return this.clientId;
|
|
131
|
+
}
|
|
132
|
+
;
|
|
133
|
+
}
|
|
134
|
+
exports.ResilienceManager = ResilienceManager;
|
|
135
|
+
;
|
|
@@ -49,6 +49,14 @@ export const isValidPhone = async (axiosClient, phone, rules) => {
|
|
|
49
49
|
reasons.push("FRAUD");
|
|
50
50
|
if (rules.deny.includes("HIGH_RISK_SCORE") && responsePhone.plugins.riskScore >= 80)
|
|
51
51
|
reasons.push("HIGH_RISK_SCORE");
|
|
52
|
+
// Country block rules.
|
|
53
|
+
for (const rule of rules.deny) {
|
|
54
|
+
if (rule.startsWith("COUNTRY:")) {
|
|
55
|
+
const block = rule.split(":")[1]; // Extract country code.
|
|
56
|
+
if (responsePhone.countryCode === block)
|
|
57
|
+
reasons.push(`COUNTRY:${block}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
52
60
|
return {
|
|
53
61
|
phone: responsePhone.phone,
|
|
54
62
|
allow: reasons.length === 0,
|
package/dist/esm/dymo-api.js
CHANGED
|
@@ -3,25 +3,29 @@ import axios from "axios";
|
|
|
3
3
|
import { validBaseURL } from "./utils/basics.js";
|
|
4
4
|
import * as PublicAPI from "./branches/public/index.js";
|
|
5
5
|
import * as PrivateAPI from "./branches/private/index.js";
|
|
6
|
+
import { ResilienceManager } from "./lib/resilience/index.js";
|
|
7
|
+
import { FallbackDataGenerator } from "./lib/resilience/fallback.js";
|
|
6
8
|
class DymoAPI {
|
|
7
9
|
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
* @param {Object} options - Options to create the DymoAPI instance.
|
|
11
|
+
* @param {string} [options.rootApiKey] - The root API key.
|
|
12
|
+
* @param {string} [options.apiKey] - The API key.
|
|
13
|
+
* @param {string} [options.baseUrl] - Whether to use a local server instead of the cloud server.
|
|
14
|
+
* @param {Object} [options.serverEmailConfig] - The server email config.
|
|
15
|
+
* @param {Object} [options.rules] - The rules.
|
|
16
|
+
* @param {Object} [options.resilience] - The resilience config.
|
|
17
|
+
* @description
|
|
18
|
+
* This is the main class to interact with the Dymo API. It should be
|
|
19
|
+
* instantiated with the root API key and the API key. The root API key is
|
|
20
|
+
* used to fetch the tokens and the API key is used to authenticate the
|
|
21
|
+
* requests. Requests are retried once by default with exponential backoff.
|
|
22
|
+
* @example
|
|
23
|
+
* const dymoApi = new DymoAPI({
|
|
24
|
+
* rootApiKey: "6bfb7675-6b69-4f8d-9f43-5a6f7f02c6c5",
|
|
25
|
+
* apiKey: "dm_4c8b7675-6b69-4f8d-9f43-5a6f7f02c6c5"
|
|
26
|
+
* });
|
|
27
|
+
*/
|
|
28
|
+
constructor({ rootApiKey = null, apiKey = null, baseUrl = "https://api.tpeoficial.com", serverEmailConfig = undefined, rules = {}, resilience = {} } = {}) {
|
|
25
29
|
this.rules = {
|
|
26
30
|
email: { mode: "LIVE", deny: ["FRAUD", "INVALID", "NO_MX_RECORDS", "NO_REPLY_EMAIL"] },
|
|
27
31
|
ip: { mode: "LIVE", deny: ["FRAUD", "INVALID", "TOR_NETWORK"] },
|
|
@@ -34,13 +38,16 @@ class DymoAPI {
|
|
|
34
38
|
this.apiKey = apiKey;
|
|
35
39
|
this.serverEmailConfig = serverEmailConfig;
|
|
36
40
|
this.baseUrl = baseUrl;
|
|
41
|
+
// Initialize resilience system with client ID
|
|
42
|
+
const clientId = this.apiKey || this.rootApiKey || "anonymous";
|
|
43
|
+
this.resilienceManager = new ResilienceManager(resilience, clientId);
|
|
37
44
|
// We created the Axios client with the appropriate settings.
|
|
38
45
|
this.axiosClient = axios.create({
|
|
39
46
|
baseURL: `${validBaseURL(this.baseUrl)}/v1`,
|
|
40
47
|
headers: {
|
|
41
48
|
"User-Agent": "DymoAPISDK/1.0.0",
|
|
42
49
|
"X-Dymo-SDK-Env": "Node",
|
|
43
|
-
"X-Dymo-SDK-Version": "1.2.
|
|
50
|
+
"X-Dymo-SDK-Version": "1.2.31"
|
|
44
51
|
}
|
|
45
52
|
});
|
|
46
53
|
// We set the authorization in the Axios client to make requests.
|
|
@@ -48,6 +55,14 @@ class DymoAPI {
|
|
|
48
55
|
this.axiosClient.defaults.headers.Authorization = `Bearer ${this.rootApiKey || this.apiKey}`;
|
|
49
56
|
}
|
|
50
57
|
;
|
|
58
|
+
getEmailPlugins(rules) {
|
|
59
|
+
return [
|
|
60
|
+
rules.deny.includes("NO_MX_RECORDS") ? "mxRecords" : undefined,
|
|
61
|
+
rules.deny.includes("NO_REACHABLE") ? "reachable" : undefined,
|
|
62
|
+
rules.deny.includes("HIGH_RISK_SCORE") ? "riskScore" : undefined,
|
|
63
|
+
rules.deny.includes("NO_GRAVATAR") ? "gravatar" : undefined
|
|
64
|
+
].filter(Boolean);
|
|
65
|
+
}
|
|
51
66
|
// FUNCTIONS / Private.
|
|
52
67
|
/**
|
|
53
68
|
* Validates the given data against the configured validation settings.
|
|
@@ -73,7 +88,12 @@ class DymoAPI {
|
|
|
73
88
|
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier)
|
|
74
89
|
*/
|
|
75
90
|
async isValidData(data) {
|
|
76
|
-
|
|
91
|
+
const fallbackData = FallbackDataGenerator.generateFallbackData("isValidData", data);
|
|
92
|
+
return await this.resilienceManager.executeWithResilience(this.axiosClient, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
url: "/private/secure/verify",
|
|
95
|
+
data
|
|
96
|
+
}, this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : undefined);
|
|
77
97
|
}
|
|
78
98
|
;
|
|
79
99
|
/**
|
|
@@ -99,7 +119,12 @@ class DymoAPI {
|
|
|
99
119
|
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier)
|
|
100
120
|
*/
|
|
101
121
|
async isValidDataRaw(data) {
|
|
102
|
-
|
|
122
|
+
const fallbackData = FallbackDataGenerator.generateFallbackData("isValidDataRaw", data);
|
|
123
|
+
return await this.resilienceManager.executeWithResilience(this.axiosClient, {
|
|
124
|
+
method: "POST",
|
|
125
|
+
url: "/private/secure/verify",
|
|
126
|
+
data
|
|
127
|
+
}, this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : undefined);
|
|
103
128
|
}
|
|
104
129
|
;
|
|
105
130
|
/**
|
|
@@ -121,7 +146,12 @@ class DymoAPI {
|
|
|
121
146
|
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/email-validation)
|
|
122
147
|
*/
|
|
123
148
|
async isValidEmail(email, rules = this.rules.email) {
|
|
124
|
-
|
|
149
|
+
const fallbackData = FallbackDataGenerator.generateFallbackData("isValidEmail", email);
|
|
150
|
+
return await this.resilienceManager.executeWithResilience(this.axiosClient, {
|
|
151
|
+
method: "POST",
|
|
152
|
+
url: "/private/secure/verify",
|
|
153
|
+
data: { email, plugins: this.getEmailPlugins(rules) }
|
|
154
|
+
}, this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : undefined);
|
|
125
155
|
}
|
|
126
156
|
;
|
|
127
157
|
/**
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
export class FallbackDataGenerator {
|
|
2
|
+
static generateFallbackData(method, inputData) {
|
|
3
|
+
switch (method) {
|
|
4
|
+
case "isValidData": return this.generateDataValidationAnalysis(inputData);
|
|
5
|
+
case "isValidEmail": return this.generateEmailValidatorResponse(inputData);
|
|
6
|
+
case "isValidIP": return this.generateIPValidatorResponse(inputData);
|
|
7
|
+
case "isValidPhone": return this.generatePhoneValidatorResponse(inputData);
|
|
8
|
+
case "protectReq": return this.generateHTTPRequest(inputData);
|
|
9
|
+
case "sendEmail": return this.generateEmailStatus();
|
|
10
|
+
case "getRandom": return this.generateSRNSummary(inputData);
|
|
11
|
+
case "extractWithTextly": return this.generateExtractWithTextly(inputData);
|
|
12
|
+
case "getPrayerTimes": return this.generatePrayerTimes(inputData);
|
|
13
|
+
case "satinize": return this.generateSatinizedInputAnalysis(inputData);
|
|
14
|
+
case "isValidPwd": return this.generatePasswordValidationResult(inputData);
|
|
15
|
+
default: throw new Error(`Unknown method for fallback: ${method}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
;
|
|
19
|
+
static validateURL(url) {
|
|
20
|
+
if (!url)
|
|
21
|
+
return false;
|
|
22
|
+
const urlRegex = /^https?:\/\/(?:[-\w.])+(?:\:[0-9]+)?(?:\/(?:[\w\/_.])*(?:\?(?:[\w&=%.])*)?(?:\#(?:[\w.])*)?)?$/;
|
|
23
|
+
return urlRegex.test(url);
|
|
24
|
+
}
|
|
25
|
+
;
|
|
26
|
+
static validateEmail(email) {
|
|
27
|
+
if (!email)
|
|
28
|
+
return false;
|
|
29
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
30
|
+
return emailRegex.test(email);
|
|
31
|
+
}
|
|
32
|
+
;
|
|
33
|
+
static validateDomain(domain) {
|
|
34
|
+
if (!domain)
|
|
35
|
+
return false;
|
|
36
|
+
const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])*$/;
|
|
37
|
+
if (!domainRegex.test(domain))
|
|
38
|
+
return false;
|
|
39
|
+
// Validar que tenga un TLD (último punto + contenido)
|
|
40
|
+
const parts = domain.split('.');
|
|
41
|
+
return parts.length >= 2 && parts[parts.length - 1].length > 0;
|
|
42
|
+
}
|
|
43
|
+
;
|
|
44
|
+
static validateCreditCard(creditCard) {
|
|
45
|
+
if (!creditCard)
|
|
46
|
+
return false;
|
|
47
|
+
const cardNumber = typeof creditCard === "string" ? creditCard : creditCard?.pan || "";
|
|
48
|
+
if (!cardNumber)
|
|
49
|
+
return false;
|
|
50
|
+
const cardRegex = /^\d{13,19}$/;
|
|
51
|
+
if (!cardRegex.test(cardNumber.replace(/\s/g, "")))
|
|
52
|
+
return false;
|
|
53
|
+
// Luhn algorithm
|
|
54
|
+
const digits = cardNumber.replace(/\s/g, "").split("").map(Number);
|
|
55
|
+
let sum = 0;
|
|
56
|
+
let isEven = false;
|
|
57
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
58
|
+
let digit = digits[i];
|
|
59
|
+
if (isEven) {
|
|
60
|
+
digit *= 2;
|
|
61
|
+
if (digit > 9)
|
|
62
|
+
digit -= 9;
|
|
63
|
+
}
|
|
64
|
+
sum += digit;
|
|
65
|
+
isEven = !isEven;
|
|
66
|
+
}
|
|
67
|
+
return sum % 10 === 0;
|
|
68
|
+
}
|
|
69
|
+
;
|
|
70
|
+
static validateIP(ip) {
|
|
71
|
+
if (!ip)
|
|
72
|
+
return false;
|
|
73
|
+
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
74
|
+
const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
75
|
+
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
|
76
|
+
}
|
|
77
|
+
;
|
|
78
|
+
static validatePhone(phone) {
|
|
79
|
+
if (!phone)
|
|
80
|
+
return false;
|
|
81
|
+
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
|
|
82
|
+
return phoneRegex.test(phone.replace(/[^\d+]/g, ""));
|
|
83
|
+
}
|
|
84
|
+
;
|
|
85
|
+
static validateWallet(wallet) {
|
|
86
|
+
if (!wallet)
|
|
87
|
+
return false;
|
|
88
|
+
const bitcoinRegex = /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/;
|
|
89
|
+
const ethereumRegex = /^0x[a-fA-F0-9]{40}$/;
|
|
90
|
+
return bitcoinRegex.test(wallet) || ethereumRegex.test(wallet);
|
|
91
|
+
}
|
|
92
|
+
;
|
|
93
|
+
static validateIBAN(iban) {
|
|
94
|
+
if (!iban)
|
|
95
|
+
return false;
|
|
96
|
+
const ibanRegex = /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/;
|
|
97
|
+
return ibanRegex.test(iban.replace(/\s/g, "").toUpperCase());
|
|
98
|
+
}
|
|
99
|
+
;
|
|
100
|
+
static extractDomain(url) {
|
|
101
|
+
if (!url)
|
|
102
|
+
return "";
|
|
103
|
+
try {
|
|
104
|
+
return new URL(url).hostname;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return "";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
;
|
|
111
|
+
static generateDataValidationAnalysis(inputData) {
|
|
112
|
+
return {
|
|
113
|
+
url: {
|
|
114
|
+
valid: this.validateURL(inputData?.url),
|
|
115
|
+
fraud: false,
|
|
116
|
+
freeSubdomain: false,
|
|
117
|
+
customTLD: false,
|
|
118
|
+
url: inputData?.url || "",
|
|
119
|
+
domain: this.extractDomain(inputData?.url),
|
|
120
|
+
plugins: {
|
|
121
|
+
blocklist: false,
|
|
122
|
+
compromiseDetector: false,
|
|
123
|
+
mxRecords: [],
|
|
124
|
+
nsfw: false,
|
|
125
|
+
reputation: "unknown",
|
|
126
|
+
riskScore: 0,
|
|
127
|
+
torNetwork: false,
|
|
128
|
+
typosquatting: 0,
|
|
129
|
+
urlShortener: false
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
email: this.generateEmailDataAnalysis(inputData?.email),
|
|
133
|
+
phone: this.generatePhoneDataAnalysis(inputData?.phone),
|
|
134
|
+
domain: {
|
|
135
|
+
valid: this.validateDomain(inputData?.domain),
|
|
136
|
+
fraud: false,
|
|
137
|
+
freeSubdomain: false,
|
|
138
|
+
customTLD: false,
|
|
139
|
+
domain: inputData?.domain || "",
|
|
140
|
+
plugins: {
|
|
141
|
+
blocklist: false,
|
|
142
|
+
compromiseDetector: false,
|
|
143
|
+
mxRecords: [],
|
|
144
|
+
nsfw: false,
|
|
145
|
+
reputation: "unknown",
|
|
146
|
+
riskScore: 0,
|
|
147
|
+
torNetwork: false,
|
|
148
|
+
typosquatting: 0,
|
|
149
|
+
urlShortener: false
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
creditCard: {
|
|
153
|
+
valid: this.validateCreditCard(inputData?.creditCard),
|
|
154
|
+
fraud: false,
|
|
155
|
+
test: false,
|
|
156
|
+
type: "unknown",
|
|
157
|
+
creditCard: typeof inputData?.creditCard === "string" ? inputData.creditCard : inputData?.creditCard?.pan || "",
|
|
158
|
+
plugins: {
|
|
159
|
+
blocklist: false,
|
|
160
|
+
riskScore: 0
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
ip: this.generateIPDataAnalysis(inputData?.ip),
|
|
164
|
+
wallet: {
|
|
165
|
+
valid: this.validateWallet(inputData?.wallet),
|
|
166
|
+
fraud: false,
|
|
167
|
+
wallet: inputData?.wallet || "",
|
|
168
|
+
type: "unknown",
|
|
169
|
+
plugins: {
|
|
170
|
+
blocklist: false,
|
|
171
|
+
riskScore: 0,
|
|
172
|
+
torNetwork: false
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
userAgent: {
|
|
176
|
+
valid: false,
|
|
177
|
+
fraud: false,
|
|
178
|
+
userAgent: inputData?.userAgent || "",
|
|
179
|
+
bot: true,
|
|
180
|
+
device: { type: "unknown", brand: "unknown" },
|
|
181
|
+
plugins: {
|
|
182
|
+
blocklist: false,
|
|
183
|
+
riskScore: 0
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
iban: {
|
|
187
|
+
valid: this.validateIBAN(inputData?.iban),
|
|
188
|
+
fraud: false,
|
|
189
|
+
iban: inputData?.iban || "",
|
|
190
|
+
plugins: {
|
|
191
|
+
blocklist: false,
|
|
192
|
+
riskScore: 0
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
;
|
|
198
|
+
static generateEmailValidatorResponse(inputData) {
|
|
199
|
+
return {
|
|
200
|
+
email: inputData?.email || "",
|
|
201
|
+
allow: this.validateEmail(inputData?.email),
|
|
202
|
+
reasons: this.validateEmail(inputData?.email) ? [] : ["INVALID"],
|
|
203
|
+
response: this.generateEmailDataAnalysis(inputData?.email)
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
;
|
|
207
|
+
static generateEmailDataAnalysis(email) {
|
|
208
|
+
return {
|
|
209
|
+
valid: this.validateEmail(email),
|
|
210
|
+
fraud: false,
|
|
211
|
+
proxiedEmail: false,
|
|
212
|
+
freeSubdomain: false,
|
|
213
|
+
corporate: false,
|
|
214
|
+
email: email || "",
|
|
215
|
+
realUser: "",
|
|
216
|
+
didYouMean: null,
|
|
217
|
+
noReply: false,
|
|
218
|
+
customTLD: false,
|
|
219
|
+
domain: "",
|
|
220
|
+
roleAccount: false,
|
|
221
|
+
plugins: {
|
|
222
|
+
mxRecords: [],
|
|
223
|
+
blocklist: false,
|
|
224
|
+
compromiseDetector: false,
|
|
225
|
+
nsfw: false,
|
|
226
|
+
reputation: "unknown",
|
|
227
|
+
riskScore: 0,
|
|
228
|
+
torNetwork: false,
|
|
229
|
+
typosquatting: 0,
|
|
230
|
+
urlShortener: false
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
;
|
|
235
|
+
static generateIPValidatorResponse(inputData) {
|
|
236
|
+
return {
|
|
237
|
+
ip: inputData?.ip || "",
|
|
238
|
+
allow: this.validateIP(inputData?.ip),
|
|
239
|
+
reasons: this.validateIP(inputData?.ip) ? [] : ["INVALID"],
|
|
240
|
+
response: this.generateIPDataAnalysis(inputData?.ip)
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
;
|
|
244
|
+
static generateIPDataAnalysis(ip) {
|
|
245
|
+
const isValid = this.validateIP(ip);
|
|
246
|
+
return {
|
|
247
|
+
valid: isValid,
|
|
248
|
+
type: isValid ? "IPv4" : "Invalid",
|
|
249
|
+
class: isValid ? "A" : "Unknown",
|
|
250
|
+
fraud: false,
|
|
251
|
+
ip: ip || "",
|
|
252
|
+
continent: "",
|
|
253
|
+
continentCode: "",
|
|
254
|
+
country: "",
|
|
255
|
+
countryCode: "",
|
|
256
|
+
region: "",
|
|
257
|
+
regionName: "",
|
|
258
|
+
city: "",
|
|
259
|
+
district: "",
|
|
260
|
+
zipCode: "",
|
|
261
|
+
lat: 0,
|
|
262
|
+
lon: 0,
|
|
263
|
+
timezone: "",
|
|
264
|
+
offset: 0,
|
|
265
|
+
currency: "",
|
|
266
|
+
isp: "",
|
|
267
|
+
org: "",
|
|
268
|
+
as: "",
|
|
269
|
+
asname: "",
|
|
270
|
+
mobile: false,
|
|
271
|
+
proxy: true,
|
|
272
|
+
hosting: false,
|
|
273
|
+
plugins: {
|
|
274
|
+
blocklist: false,
|
|
275
|
+
riskScore: 0
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
;
|
|
280
|
+
static generatePhoneValidatorResponse(inputData) {
|
|
281
|
+
return {
|
|
282
|
+
phone: inputData?.phone || "",
|
|
283
|
+
allow: this.validatePhone(inputData?.phone),
|
|
284
|
+
reasons: this.validatePhone(inputData?.phone) ? [] : ["INVALID"],
|
|
285
|
+
response: this.generatePhoneDataAnalysis(inputData?.phone)
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
;
|
|
289
|
+
static generatePhoneDataAnalysis(phone) {
|
|
290
|
+
const phoneNumber = phone?.phone || phone;
|
|
291
|
+
const isValid = this.validatePhone(phoneNumber);
|
|
292
|
+
return {
|
|
293
|
+
valid: isValid,
|
|
294
|
+
fraud: false,
|
|
295
|
+
phone: phone?.phone || "",
|
|
296
|
+
prefix: "",
|
|
297
|
+
number: "",
|
|
298
|
+
lineType: "Unknown",
|
|
299
|
+
carrierInfo: {
|
|
300
|
+
carrierName: "",
|
|
301
|
+
accuracy: 0,
|
|
302
|
+
carrierCountry: "",
|
|
303
|
+
carrierCountryCode: ""
|
|
304
|
+
},
|
|
305
|
+
country: "",
|
|
306
|
+
countryCode: "",
|
|
307
|
+
plugins: {
|
|
308
|
+
blocklist: false,
|
|
309
|
+
riskScore: 0
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
;
|
|
314
|
+
static generateHTTPRequest(inputData) {
|
|
315
|
+
return {
|
|
316
|
+
method: inputData?.method || "GET",
|
|
317
|
+
url: inputData?.url || "",
|
|
318
|
+
headers: inputData?.headers || {},
|
|
319
|
+
body: inputData?.body || null,
|
|
320
|
+
allow: false,
|
|
321
|
+
reasons: ["FRAUD"],
|
|
322
|
+
protected: true
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
;
|
|
326
|
+
static generateEmailStatus() {
|
|
327
|
+
return {
|
|
328
|
+
status: false,
|
|
329
|
+
error: "API unavailable - using fallback response"
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
;
|
|
333
|
+
static generateSRNSummary(inputData) {
|
|
334
|
+
const quantity = inputData?.quantity || 1;
|
|
335
|
+
const values = Array.from({ length: quantity }, () => ({
|
|
336
|
+
integer: 0,
|
|
337
|
+
float: 0.0
|
|
338
|
+
}));
|
|
339
|
+
return {
|
|
340
|
+
values,
|
|
341
|
+
executionTime: 0
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
;
|
|
345
|
+
static generateExtractWithTextly(inputData) {
|
|
346
|
+
return {
|
|
347
|
+
data: inputData?.data || "",
|
|
348
|
+
extracted: {},
|
|
349
|
+
error: "API unavailable - using fallback response"
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
;
|
|
353
|
+
static generatePrayerTimes(inputData) {
|
|
354
|
+
return {
|
|
355
|
+
error: "API unavailable - using fallback response"
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
;
|
|
359
|
+
static generateSatinizedInputAnalysis(inputData) {
|
|
360
|
+
return {
|
|
361
|
+
input: inputData?.input || "",
|
|
362
|
+
formats: {
|
|
363
|
+
ascii: false,
|
|
364
|
+
bitcoinAddress: false,
|
|
365
|
+
cLikeIdentifier: false,
|
|
366
|
+
coordinates: false,
|
|
367
|
+
crediCard: false,
|
|
368
|
+
date: false,
|
|
369
|
+
discordUsername: false,
|
|
370
|
+
doi: false,
|
|
371
|
+
domain: false,
|
|
372
|
+
e164Phone: false,
|
|
373
|
+
email: false,
|
|
374
|
+
emoji: false,
|
|
375
|
+
hanUnification: false,
|
|
376
|
+
hashtag: false,
|
|
377
|
+
hyphenWordBreak: false,
|
|
378
|
+
ipv6: false,
|
|
379
|
+
ip: false,
|
|
380
|
+
jiraTicket: false,
|
|
381
|
+
macAddress: false,
|
|
382
|
+
name: false,
|
|
383
|
+
number: false,
|
|
384
|
+
panFromGstin: false,
|
|
385
|
+
password: false,
|
|
386
|
+
port: false,
|
|
387
|
+
tel: false,
|
|
388
|
+
text: false,
|
|
389
|
+
semver: false,
|
|
390
|
+
ssn: false,
|
|
391
|
+
uuid: false,
|
|
392
|
+
url: false,
|
|
393
|
+
urlSlug: false,
|
|
394
|
+
username: false
|
|
395
|
+
},
|
|
396
|
+
includes: {
|
|
397
|
+
spaces: false,
|
|
398
|
+
hasSql: false,
|
|
399
|
+
hasNoSql: false,
|
|
400
|
+
letters: false,
|
|
401
|
+
uppercase: false,
|
|
402
|
+
lowercase: false,
|
|
403
|
+
symbols: false,
|
|
404
|
+
digits: false
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
;
|
|
409
|
+
static generatePasswordValidationResult(inputData) {
|
|
410
|
+
return {
|
|
411
|
+
valid: false,
|
|
412
|
+
password: inputData?.password || "",
|
|
413
|
+
details: [
|
|
414
|
+
{
|
|
415
|
+
validation: "length",
|
|
416
|
+
message: "API unavailable - using fallback response"
|
|
417
|
+
}
|
|
418
|
+
]
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
;
|
|
422
|
+
}
|
|
423
|
+
;
|