dymo-api 1.2.32 → 1.2.33
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/dymo-api.cjs +1123 -393
- package/dist/esm/dymo-api.js +1125 -356
- package/dist/types/branches/private/functions/extractWithTextly/index.d.ts +3 -2
- package/dist/types/branches/private/functions/extractWithTextly/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/getRandom/index.d.ts +3 -2
- package/dist/types/branches/private/functions/getRandom/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/isValidDataRaw/index.d.ts +3 -2
- package/dist/types/branches/private/functions/isValidDataRaw/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/isValidEmail/index.d.ts +3 -2
- package/dist/types/branches/private/functions/isValidEmail/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/isValidIP/index.d.ts +3 -2
- package/dist/types/branches/private/functions/isValidIP/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/isValidPhone/index.d.ts +3 -2
- package/dist/types/branches/private/functions/isValidPhone/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/protectReq/index.d.ts +3 -2
- package/dist/types/branches/private/functions/protectReq/index.d.ts.map +1 -0
- package/dist/types/branches/private/functions/protectReq/requestHandler.d.ts +1 -0
- package/dist/types/branches/private/functions/protectReq/requestHandler.d.ts.map +1 -0
- package/dist/types/branches/private/functions/sendEmail/index.d.ts +3 -2
- package/dist/types/branches/private/functions/sendEmail/index.d.ts.map +1 -0
- package/dist/types/branches/private/index.d.ts +9 -8
- package/dist/types/branches/private/index.d.ts.map +1 -0
- package/dist/types/branches/public/functions/getPrayerTimes/index.d.ts +3 -2
- package/dist/types/branches/public/functions/getPrayerTimes/index.d.ts.map +1 -0
- package/dist/types/branches/public/functions/isValidPwd/index.d.ts +3 -2
- package/dist/types/branches/public/functions/isValidPwd/index.d.ts.map +1 -0
- package/dist/types/branches/public/functions/satinize/index.d.ts +2 -1
- package/dist/types/branches/public/functions/satinize/index.d.ts.map +1 -0
- package/dist/types/branches/public/index.d.ts +4 -3
- package/dist/types/branches/public/index.d.ts.map +1 -0
- package/dist/types/config/index.d.ts +1 -0
- package/dist/types/config/index.d.ts.map +1 -0
- package/dist/types/dymo-api.d.ts +2 -1
- package/dist/types/dymo-api.d.ts.map +1 -0
- package/dist/types/lib/resilience/fallback.d.ts +1 -0
- package/dist/types/lib/resilience/fallback.d.ts.map +1 -0
- package/dist/types/lib/resilience/index.d.ts +3 -2
- package/dist/types/lib/resilience/index.d.ts.map +1 -0
- package/dist/types/lib/types/data-verifier.d.ts +3 -2
- package/dist/types/lib/types/data-verifier.d.ts.map +1 -0
- package/dist/types/lib/types/interfaces.d.ts +5 -4
- package/dist/types/lib/types/interfaces.d.ts.map +1 -0
- package/dist/types/lib/types/primitives.d.ts +1 -0
- package/dist/types/lib/types/primitives.d.ts.map +1 -0
- package/dist/types/lib/types/rules.d.ts +2 -1
- package/dist/types/lib/types/rules.d.ts.map +1 -0
- package/dist/types/lib/types/well-known-bots.d.ts +1 -0
- package/dist/types/lib/types/well-known-bots.d.ts.map +1 -0
- package/dist/types/utils/basics.d.ts +1 -0
- package/dist/types/utils/basics.d.ts.map +1 -0
- package/package.json +8 -9
- package/dist/cjs/branches/private/functions/extractWithTextly/index.cjs +0 -33
- package/dist/cjs/branches/private/functions/getRandom/index.cjs +0 -37
- package/dist/cjs/branches/private/functions/isValidDataRaw/index.cjs +0 -33
- package/dist/cjs/branches/private/functions/isValidEmail/index.cjs +0 -91
- package/dist/cjs/branches/private/functions/isValidIP/index.cjs +0 -80
- package/dist/cjs/branches/private/functions/isValidPhone/index.cjs +0 -77
- package/dist/cjs/branches/private/functions/protectReq/index.cjs +0 -74
- package/dist/cjs/branches/private/functions/protectReq/requestHandler.cjs +0 -22
- package/dist/cjs/branches/private/functions/sendEmail/index.cjs +0 -88
- package/dist/cjs/branches/private/index.cjs +0 -24
- package/dist/cjs/branches/public/functions/getPrayerTimes/index.cjs +0 -31
- package/dist/cjs/branches/public/functions/isValidPwd/index.cjs +0 -65
- package/dist/cjs/branches/public/functions/satinize/index.cjs +0 -26
- package/dist/cjs/branches/public/index.cjs +0 -19
- package/dist/cjs/config/index.cjs +0 -12
- package/dist/cjs/lib/resilience/fallback.cjs +0 -427
- package/dist/cjs/lib/resilience/index.cjs +0 -135
- package/dist/cjs/lib/types/data-verifier.cjs +0 -2
- package/dist/cjs/lib/types/interfaces.cjs +0 -24
- package/dist/cjs/lib/types/primitives.cjs +0 -2
- package/dist/cjs/lib/types/rules.cjs +0 -2
- package/dist/cjs/lib/types/well-known-bots.cjs +0 -739
- package/dist/cjs/utils/basics.cjs +0 -18
- package/dist/esm/branches/private/functions/extractWithTextly/index.js +0 -29
- package/dist/esm/branches/private/functions/getRandom/index.js +0 -33
- package/dist/esm/branches/private/functions/isValidDataRaw/index.js +0 -29
- package/dist/esm/branches/private/functions/isValidEmail/index.js +0 -87
- package/dist/esm/branches/private/functions/isValidIP/index.js +0 -76
- package/dist/esm/branches/private/functions/isValidPhone/index.js +0 -73
- package/dist/esm/branches/private/functions/protectReq/index.js +0 -37
- package/dist/esm/branches/private/functions/protectReq/requestHandler.js +0 -18
- package/dist/esm/branches/private/functions/sendEmail/index.js +0 -81
- package/dist/esm/branches/private/index.js +0 -8
- package/dist/esm/branches/public/functions/getPrayerTimes/index.js +0 -27
- package/dist/esm/branches/public/functions/isValidPwd/index.js +0 -61
- package/dist/esm/branches/public/functions/satinize/index.js +0 -22
- package/dist/esm/branches/public/index.js +0 -3
- package/dist/esm/config/index.js +0 -10
- package/dist/esm/lib/resilience/fallback.js +0 -423
- package/dist/esm/lib/resilience/index.js +0 -131
- package/dist/esm/lib/types/data-verifier.js +0 -1
- package/dist/esm/lib/types/interfaces.js +0 -8
- package/dist/esm/lib/types/primitives.js +0 -1
- package/dist/esm/lib/types/rules.js +0 -1
- package/dist/esm/lib/types/well-known-bots.js +0 -736
- package/dist/esm/utils/basics.js +0 -10
package/dist/cjs/dymo-api.cjs
CHANGED
|
@@ -1,408 +1,1138 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
2
|
+
const axios = require("axios");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const twToCss = require("tw-to-css");
|
|
6
|
+
const render = require("@react-email/render");
|
|
7
|
+
const config = {
|
|
8
|
+
lib: {
|
|
9
|
+
name: "Dymo API"
|
|
10
|
+
}
|
|
37
11
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
* If neither is set, it will throw an error.
|
|
142
|
-
*
|
|
143
|
-
* @param {Object} data - The data to be validated.
|
|
144
|
-
* @param {string} [data.url] - Optional URL to be validated.
|
|
145
|
-
* @param {string} [data.email] - Optional email address to be validated.
|
|
146
|
-
* @param {Interfaces.PhoneData} [data.phone] - Optional phone number data to be validated.
|
|
147
|
-
* @param {string} [data.domain] - Optional domain name to be validated.
|
|
148
|
-
* @param {string|Interfaces.CreditCardData} [data.creditCard] - Optional credit card number or data to be validated.
|
|
149
|
-
* @param {string} [data.ip] - Optional IP address to be validated.
|
|
150
|
-
* @param {string} [data.wallet] - Optional wallet address to be validated.
|
|
151
|
-
* @param {string} [data.userAgent] - Optional user agent string to be validated.
|
|
152
|
-
* @param {string} [data.iban] - Optional IBAN to be validated.
|
|
153
|
-
* @param {Interfaces.VerifyPlugins[]} [data.plugins] - Optional array of verification plugins to be used.
|
|
154
|
-
* @returns {Promise<Interfaces.DataValidationAnalysis>} A promise that resolves to the response from the server.
|
|
155
|
-
* @throws Will throw an error if there is an issue with the validation process.
|
|
156
|
-
*
|
|
157
|
-
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier)
|
|
158
|
-
*/
|
|
159
|
-
async isValidDataRaw(data) {
|
|
160
|
-
const fallbackData = fallback_1.FallbackDataGenerator.generateFallbackData("isValidDataRaw", data);
|
|
161
|
-
return await this.resilienceManager.executeWithResilience(this.axiosClient, {
|
|
162
|
-
method: "POST",
|
|
163
|
-
url: "/private/secure/verify",
|
|
164
|
-
data
|
|
165
|
-
}, this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : undefined);
|
|
12
|
+
const customError = (code, message) => {
|
|
13
|
+
return Object.assign(new Error(), { code, message: `[${config.lib.name}] ${message}` });
|
|
14
|
+
};
|
|
15
|
+
const validBaseURL = (baseUrl) => {
|
|
16
|
+
if (/^(https:\/\/api\.tpeoficial\.com$|http:\/\/(localhost:\d+|dymoapi:\d+))$/.test(baseUrl)) return baseUrl;
|
|
17
|
+
else throw new Error("[Dymo API] Invalid URL. It must be https://api.tpeoficial.com or start with http://localhost or http://dymoapi followed by a port.");
|
|
18
|
+
};
|
|
19
|
+
const getPrayerTimes = async (axiosClient, data) => {
|
|
20
|
+
const { lat, lon } = data;
|
|
21
|
+
if (lat === void 0 || lon === void 0) throw customError(1e3, "You must provide a latitude and longitude.");
|
|
22
|
+
try {
|
|
23
|
+
const response = await axiosClient.get("/public/islam/prayertimes", { params: data });
|
|
24
|
+
return response.data;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw customError(5e3, error.response?.data?.message || error.message);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const isValidPwd = async (axiosClient, data) => {
|
|
30
|
+
let { email, password, bannedWords, min, max } = data;
|
|
31
|
+
if (password === void 0) throw customError(1e3, "You must specify at least the password.");
|
|
32
|
+
const params = { password: encodeURIComponent(password) };
|
|
33
|
+
if (email) {
|
|
34
|
+
if (!/^[a-zA-Z0-9._\-+]+@?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(email)) throw customError(1500, "If you provide an email address it must be valid.");
|
|
35
|
+
params.email = encodeURIComponent(email);
|
|
36
|
+
}
|
|
37
|
+
if (bannedWords) {
|
|
38
|
+
if (typeof bannedWords === "string") bannedWords = bannedWords.slice(1, -1).trim().split(",").map((item) => item.trim());
|
|
39
|
+
if (!Array.isArray(bannedWords) || bannedWords.length > 10) throw customError(1500, "If you provide a list of banned words; the list may not exceed 10 words and must be of array type.");
|
|
40
|
+
if (!bannedWords.every((word) => typeof word === "string") || new Set(bannedWords).size !== bannedWords.length) throw customError(1500, "If you provide a list of banned words; all elements must be non-repeated strings.");
|
|
41
|
+
params.bannedWords = bannedWords;
|
|
42
|
+
}
|
|
43
|
+
if (min !== void 0 && (!Number.isInteger(min) || min < 8 || min > 32)) throw customError(1500, "If you provide a minimum it must be valid.");
|
|
44
|
+
if (max !== void 0 && (!Number.isInteger(max) || max < 32 || max > 100)) throw customError(1500, "If you provide a maximum it must be valid.");
|
|
45
|
+
if (min !== void 0) params.min = min;
|
|
46
|
+
if (max !== void 0) params.max = max;
|
|
47
|
+
try {
|
|
48
|
+
const response = await axiosClient.get("/public/validPwd", { params });
|
|
49
|
+
return response.data;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw customError(5e3, error.response?.data?.message || error.message);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const satinize = async (axiosClient, input) => {
|
|
55
|
+
if (input === void 0) throw customError(1e3, "You must specify at least the input.");
|
|
56
|
+
try {
|
|
57
|
+
const response = await axiosClient.get("/public/inputSatinizer", { params: { input: encodeURIComponent(input) } });
|
|
58
|
+
return response.data;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
throw customError(5e3, error.response?.data?.message || error.message);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const extractWithTextly = async (axiosClient, data) => {
|
|
64
|
+
if (!axiosClient.defaults.headers?.Authorization) throw customError(3e3, "Invalid private token.");
|
|
65
|
+
if (!data.data) throw customError(1500, "No data provided.");
|
|
66
|
+
if (!data.format) throw customError(1500, "No format provided.");
|
|
67
|
+
try {
|
|
68
|
+
const response = await axiosClient.post("/private/textly/extract", data, { headers: { "Content-Type": "application/json" } });
|
|
69
|
+
return response.data;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw customError(5e3, error.response?.data?.message || error.message);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const getRandom = async (axiosClient, data) => {
|
|
75
|
+
if (!axiosClient.defaults.headers?.Authorization) throw customError(3e3, "Invalid private token.");
|
|
76
|
+
if (!data.min || !data.max) throw customError(1500, "Both 'min' and 'max' parameters must be defined.");
|
|
77
|
+
if (data.min >= data.max) throw customError(1500, "'min' must be less than 'max'.");
|
|
78
|
+
if (data.min < -1e9 || data.min > 1e9) throw customError(1500, "'min' must be an integer in the interval [-1000000000}, 1000000000].");
|
|
79
|
+
if (data.max < -1e9 || data.max > 1e9) throw customError(1500, "'max' must be an integer in the interval [-1000000000}, 1000000000].");
|
|
80
|
+
try {
|
|
81
|
+
const response = await axiosClient.post("/private/srng", data, { headers: { "Content-Type": "application/json" } });
|
|
82
|
+
return response.data;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw customError(5e3, error.response?.data?.message || error.message);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const isValidIP = async (axiosClient, ip, rules) => {
|
|
88
|
+
if (!axiosClient.defaults.headers?.Authorization) throw customError(3e3, "Invalid private token.");
|
|
89
|
+
if (rules.deny.length === 0) throw customError(1500, "You must provide at least one deny rule.");
|
|
90
|
+
if (rules.mode === "DRY_RUN") {
|
|
91
|
+
console.warn("[Dymo API] DRY_RUN mode is enabled. No requests with real data will be processed until you switch to LIVE mode.");
|
|
92
|
+
return {
|
|
93
|
+
ip,
|
|
94
|
+
allow: true,
|
|
95
|
+
reasons: [],
|
|
96
|
+
response: "CHANGE TO LIVE MODE"
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const responseIP = (await axiosClient.post("/private/secure/verify", {
|
|
101
|
+
ip,
|
|
102
|
+
plugins: [
|
|
103
|
+
rules.deny.includes("TOR_NETWORK") ? "torNetwork" : void 0,
|
|
104
|
+
rules.deny.includes("HIGH_RISK_SCORE") ? "riskScore" : void 0
|
|
105
|
+
].filter(Boolean)
|
|
106
|
+
}, { headers: { "Content-Type": "application/json" } })).data.ip;
|
|
107
|
+
let reasons = [];
|
|
108
|
+
if (rules.deny.includes("INVALID") && !responseIP.valid) {
|
|
109
|
+
return {
|
|
110
|
+
ip: responseIP.ip,
|
|
111
|
+
allow: false,
|
|
112
|
+
reasons: ["INVALID"],
|
|
113
|
+
response: responseIP
|
|
114
|
+
};
|
|
166
115
|
}
|
|
167
|
-
;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
* @param {NegativeEmailRules[]} [rules] - Optional rules for validation. Some rules are premium features.
|
|
176
|
-
* @important
|
|
177
|
-
* **⚠️ NO_MX_RECORDS, HIGH_RISK_SCORE and NO_REACHABLE are [PREMIUM](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier) features.**
|
|
178
|
-
* @returns {Promise<Interfaces.EmailValidatorResponse>} Resolves with the validation response.
|
|
179
|
-
* @throws Will throw an error if validation cannot be performed.
|
|
180
|
-
*
|
|
181
|
-
* @example
|
|
182
|
-
* const valid = await dymoClient.isValidEmail("user@example.com", { deny: ["FRAUD", "NO_MX_RECORDS"] });
|
|
183
|
-
*
|
|
184
|
-
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/email-validation)
|
|
185
|
-
*/
|
|
186
|
-
async isValidEmail(email, rules = this.rules.email) {
|
|
187
|
-
const fallbackData = fallback_1.FallbackDataGenerator.generateFallbackData("isValidEmail", email);
|
|
188
|
-
return await this.resilienceManager.executeWithResilience(this.axiosClient, {
|
|
189
|
-
method: "POST",
|
|
190
|
-
url: "/private/secure/verify",
|
|
191
|
-
data: { email, plugins: this.getEmailPlugins(rules) }
|
|
192
|
-
}, this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : undefined);
|
|
116
|
+
if (rules.deny.includes("FRAUD") && responseIP.fraud) reasons.push("FRAUD");
|
|
117
|
+
if (rules.deny.includes("TOR_NETWORK") && responseIP.plugins.torNetwork) reasons.push("TOR_NETWORK");
|
|
118
|
+
if (rules.deny.includes("HIGH_RISK_SCORE") && responseIP.plugins.riskScore >= 80) reasons.push("HIGH_RISK_SCORE");
|
|
119
|
+
for (const rule of rules.deny) {
|
|
120
|
+
if (rule.startsWith("COUNTRY:")) {
|
|
121
|
+
const block = rule.split(":")[1];
|
|
122
|
+
if (responseIP.countryCode === block) reasons.push(`COUNTRY:${block}`);
|
|
123
|
+
}
|
|
193
124
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
125
|
+
return {
|
|
126
|
+
ip: responseIP.ip,
|
|
127
|
+
allow: reasons.length === 0,
|
|
128
|
+
reasons,
|
|
129
|
+
response: responseIP
|
|
130
|
+
};
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const statusCode = error.response?.status || 500;
|
|
133
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
134
|
+
const errorDetails = JSON.stringify(error.response?.data || {});
|
|
135
|
+
throw customError(5e3, `Error ${statusCode}: ${errorMessage}. Details: ${errorDetails}`);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const isValidPhone = async (axiosClient, phone, rules) => {
|
|
139
|
+
if (!axiosClient.defaults.headers?.Authorization) throw customError(3e3, "Invalid private token.");
|
|
140
|
+
if (rules.deny.length === 0) throw customError(1500, "You must provide at least one deny rule.");
|
|
141
|
+
if (rules.mode === "DRY_RUN") {
|
|
142
|
+
console.warn("[Dymo API] DRY_RUN mode is enabled. No requests with real data will be processed until you switch to LIVE mode.");
|
|
143
|
+
return {
|
|
144
|
+
phone,
|
|
145
|
+
allow: true,
|
|
146
|
+
reasons: [],
|
|
147
|
+
response: "CHANGE TO LIVE MODE"
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const responsePhone = (await axiosClient.post("/private/secure/verify", {
|
|
152
|
+
phone,
|
|
153
|
+
plugins: [
|
|
154
|
+
rules.deny.includes("HIGH_RISK_SCORE") ? "riskScore" : void 0
|
|
155
|
+
].filter(Boolean)
|
|
156
|
+
}, { headers: { "Content-Type": "application/json" } })).data.phone;
|
|
157
|
+
let reasons = [];
|
|
158
|
+
if (rules.deny.includes("INVALID") && !responsePhone.valid) {
|
|
159
|
+
return {
|
|
160
|
+
phone: responsePhone.phone,
|
|
161
|
+
allow: false,
|
|
162
|
+
reasons: ["INVALID"],
|
|
163
|
+
response: responsePhone
|
|
164
|
+
};
|
|
215
165
|
}
|
|
216
|
-
;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
* @param {string} [phone] - Phone number to validate.
|
|
224
|
-
* @param {NegativePhoneRules[]} [rules] - Optional rules for validation. Some rules are premium features.
|
|
225
|
-
* @important
|
|
226
|
-
* **⚠️ HIGH_RISK_SCORE is a [PREMIUM](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier) feature.**
|
|
227
|
-
* @returns {Promise<Interfaces.EmailValidatorResponse>} Resolves with the validation response.
|
|
228
|
-
* @throws Will throw an error if validation cannot be performed.
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* const valid = await dymoClient.isValidPhone("+34617509462", { deny: ["FRAUD", "INVALID"] });
|
|
232
|
-
*
|
|
233
|
-
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/phone-validation)
|
|
234
|
-
*/
|
|
235
|
-
async isValidPhone(phone, rules = this.rules.phone) {
|
|
236
|
-
return await PrivateAPI.isValidPhone(this.axiosClient, phone, rules);
|
|
166
|
+
if (rules.deny.includes("FRAUD") && responsePhone.fraud) reasons.push("FRAUD");
|
|
167
|
+
if (rules.deny.includes("HIGH_RISK_SCORE") && responsePhone.plugins.riskScore >= 80) reasons.push("HIGH_RISK_SCORE");
|
|
168
|
+
for (const rule of rules.deny) {
|
|
169
|
+
if (rule.startsWith("COUNTRY:")) {
|
|
170
|
+
const block = rule.split(":")[1];
|
|
171
|
+
if (responsePhone.countryCode === block) reasons.push(`COUNTRY:${block}`);
|
|
172
|
+
}
|
|
237
173
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
174
|
+
return {
|
|
175
|
+
phone: responsePhone.phone,
|
|
176
|
+
allow: reasons.length === 0,
|
|
177
|
+
reasons,
|
|
178
|
+
response: responsePhone
|
|
179
|
+
};
|
|
180
|
+
} catch (error) {
|
|
181
|
+
const statusCode = error.response?.status || 500;
|
|
182
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
183
|
+
const errorDetails = JSON.stringify(error.response?.data || {});
|
|
184
|
+
throw customError(5e3, `Error ${statusCode}: ${errorMessage}. Details: ${errorDetails}`);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const getUserAgent = (req) => {
|
|
188
|
+
return req.headers?.["user-agent"] || req.headers?.["User-Agent"];
|
|
189
|
+
};
|
|
190
|
+
const getIp = (req) => {
|
|
191
|
+
return req.ip || req.headers?.["x-forwarded-for"] || req.connection?.remoteAddress || req.socket?.remoteAddress || req.req?.socket?.remoteAddress;
|
|
192
|
+
};
|
|
193
|
+
const handleRequest = (req) => {
|
|
194
|
+
return {
|
|
195
|
+
body: req.body,
|
|
196
|
+
userAgent: getUserAgent(req),
|
|
197
|
+
ip: getIp(req)
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
const protectReq = async (axiosClient, req, rules) => {
|
|
201
|
+
if (!axiosClient.defaults.headers?.Authorization) throw customError(3e3, "Invalid private token.");
|
|
202
|
+
const reqData = handleRequest(req);
|
|
203
|
+
if (!reqData.userAgent || !reqData.ip) throw customError(1500, "You must provide user agent and ip.");
|
|
204
|
+
if (rules.mode === "DRY_RUN") {
|
|
205
|
+
console.warn("[Dymo API] DRY_RUN mode is enabled. No requests with real data will be processed until you switch to LIVE mode.");
|
|
206
|
+
return {
|
|
207
|
+
ip: reqData.ip,
|
|
208
|
+
userAgent: reqData.userAgent,
|
|
209
|
+
allow: true,
|
|
210
|
+
reasons: []
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const response = await axiosClient.post("/private/waf/verifyRequest", {
|
|
215
|
+
ip: reqData.ip,
|
|
216
|
+
userAgent: reqData.userAgent,
|
|
217
|
+
allowBots: rules.allowBots,
|
|
218
|
+
deny: rules.deny
|
|
219
|
+
}, { headers: { "Content-Type": "application/json" } });
|
|
220
|
+
return response.data;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
const statusCode = error.response?.status || 500;
|
|
223
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
224
|
+
const errorDetails = JSON.stringify(error.response?.data || {});
|
|
225
|
+
throw customError(5e3, `Error ${statusCode}: ${errorMessage}. Details: ${errorDetails}`);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const fs = {};
|
|
229
|
+
const convertTailwindToInlineCss = (htmlContent) => {
|
|
230
|
+
return htmlContent.replace(/class="([^"]+)"( style="([^"]+)")?/g, (match, classList, _, existingStyle) => {
|
|
231
|
+
const compiledStyles = twToCss.twi(classList, { minify: true, merge: true });
|
|
232
|
+
return match.replace(/class="[^"]+"/, "").replace(/ style="[^"]+"/, "").concat(` style="${existingStyle ? `${existingStyle.trim().slice(0, -1)}; ${compiledStyles}` : compiledStyles}"`);
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
const sendEmail = async (axiosClient, data) => {
|
|
236
|
+
if (!axiosClient.defaults.headers?.Authorization) throw customError(3e3, "Invalid private token.");
|
|
237
|
+
if (!data.from) throw customError(1500, "You must provide an email address from which the following will be sent.");
|
|
238
|
+
if (!data.to) throw customError(1500, "You must provide an email to be sent to.");
|
|
239
|
+
if (!data.subject) throw customError(1500, "You must provide a subject for the email to be sent.");
|
|
240
|
+
if (!data.html && !data.react && !React.isValidElement(data.react)) throw customError(1500, "You must provide HTML or a React component.");
|
|
241
|
+
if (data.html && data.react) throw customError(1500, "You must provide only HTML or a React component, not both.");
|
|
242
|
+
try {
|
|
243
|
+
if (data.react) {
|
|
244
|
+
data.html = await render.render(data.react);
|
|
245
|
+
delete data.react;
|
|
259
246
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
* This method requires either the root API key or the server email config to be set.
|
|
264
|
-
* If neither is set, it will throw an error.
|
|
265
|
-
*
|
|
266
|
-
* @param {Object} data - The email data to be sent.
|
|
267
|
-
* @param {string} data.from - The email address from which the email will be sent.
|
|
268
|
-
* @param {string} data.to - The email address to which the email will be sent.
|
|
269
|
-
* @param {string} data.subject - The subject of the email.
|
|
270
|
-
* @param {string} [data.html] - The HTML content of the email.
|
|
271
|
-
* @param {React.ReactElement} [data.react] - The React component to be rendered as the email content.
|
|
272
|
-
* @param {Object} [data.options] - Content configuration options.
|
|
273
|
-
* @param {"high" | "normal" | "low" | undefined} [data.options.priority="normal"] - Email priority (default: normal).
|
|
274
|
-
* @param {boolean} [data.options.waitToResponse=true] - Wait until the email is sent (default: true).
|
|
275
|
-
* @param {boolean} [data.options.composeTailwindClasses] - Whether to compose tailwind classes.
|
|
276
|
-
* @param {Attachment[]} [data.attachments] - An array of attachments to be included in the email.
|
|
277
|
-
* @param {string} data.attachments[].filename - The name of the attached file.
|
|
278
|
-
* @param {string} [data.attachments[].path] - The path or URL of the attached file. Either this or `content` must be provided.
|
|
279
|
-
* @param {Buffer} [data.attachments[].content] - The content of the attached file as a Buffer. Either this or `path` must be provided.
|
|
280
|
-
* @param {string} [data.attachments[].cid] - The CID (Content-ID) of the attached file, used for inline images.
|
|
281
|
-
* @returns {Promise<Interfaces.EmailStatus>} A promise that resolves to the response from the server.
|
|
282
|
-
* @throws Will throw an error if there is an issue with the email sending process.
|
|
283
|
-
*
|
|
284
|
-
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/sender-send-email/getting-started)
|
|
285
|
-
*/
|
|
286
|
-
async sendEmail(data) {
|
|
287
|
-
if (!this.serverEmailConfig && !this.rootApiKey)
|
|
288
|
-
console.error(`[${config_1.default.lib.name}] You must configure the email client settings.`);
|
|
289
|
-
return await PrivateAPI.sendEmail(this.axiosClient, { serverEmailConfig: this.serverEmailConfig, ...data });
|
|
247
|
+
if (data.options && data.options.composeTailwindClasses) {
|
|
248
|
+
data.html = convertTailwindToInlineCss(data.html);
|
|
249
|
+
delete data.options.composeTailwindClasses;
|
|
290
250
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
251
|
+
} catch (error) {
|
|
252
|
+
throw customError(1500, `An error occurred while rendering your React component. Details: ${error}`);
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
let totalSize = 0;
|
|
256
|
+
if (data.attachments && Array.isArray(data.attachments)) {
|
|
257
|
+
const processedAttachments = await Promise.all(
|
|
258
|
+
data.attachments.map(async (attachment) => {
|
|
259
|
+
if (attachment.path && attachment.content || !attachment.path && !attachment.content) throw customError(1500, "You must provide either 'path' or 'content', not both.");
|
|
260
|
+
let contentBuffer;
|
|
261
|
+
if (attachment.path) contentBuffer = await fs.readFile(path.resolve(attachment.path));
|
|
262
|
+
else if (attachment.content) contentBuffer = attachment.content instanceof Buffer ? attachment.content : Buffer.from(attachment.content);
|
|
263
|
+
totalSize += Buffer.byteLength(contentBuffer);
|
|
264
|
+
if (totalSize > 40 * 1024 * 1024) throw customError(1500, "Attachments exceed the maximum allowed size of 40 MB.");
|
|
265
|
+
return {
|
|
266
|
+
filename: attachment.filename || path.basename(attachment.path || ""),
|
|
267
|
+
content: contentBuffer,
|
|
268
|
+
cid: attachment.cid || attachment.filename
|
|
269
|
+
};
|
|
270
|
+
})
|
|
271
|
+
);
|
|
272
|
+
data.attachments = processedAttachments;
|
|
309
273
|
}
|
|
310
|
-
;
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
274
|
+
const response = await axiosClient.post("/private/sender/sendEmail", data);
|
|
275
|
+
return response.data;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
throw customError(5e3, error.response?.data?.message || error.message);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
class RateLimitManager {
|
|
281
|
+
constructor() {
|
|
282
|
+
this.tracker = {};
|
|
283
|
+
}
|
|
284
|
+
static getInstance() {
|
|
285
|
+
if (!RateLimitManager.instance) RateLimitManager.instance = new RateLimitManager();
|
|
286
|
+
return RateLimitManager.instance;
|
|
287
|
+
}
|
|
288
|
+
updateRateLimit(clientId, headers) {
|
|
289
|
+
if (!this.tracker[clientId]) this.tracker[clientId] = {};
|
|
290
|
+
const limitInfo = this.tracker[clientId];
|
|
291
|
+
if (headers["x-ratelimit-limit-requests"]) limitInfo.limit = parseInt(headers["x-ratelimit-limit-requests"]);
|
|
292
|
+
if (headers["x-ratelimit-remaining-requests"]) limitInfo.remaining = parseInt(headers["x-ratelimit-remaining-requests"]);
|
|
293
|
+
if (headers["x-ratelimit-reset-requests"]) limitInfo.resetTime = headers["x-ratelimit-reset-requests"];
|
|
294
|
+
if (headers["retry-after"]) limitInfo.retryAfter = parseInt(headers["retry-after"]);
|
|
295
|
+
limitInfo.lastUpdated = Date.now();
|
|
296
|
+
}
|
|
297
|
+
isRateLimited(clientId) {
|
|
298
|
+
const limitInfo = this.tracker[clientId];
|
|
299
|
+
return limitInfo?.remaining !== void 0 && limitInfo.remaining <= 0;
|
|
300
|
+
}
|
|
301
|
+
getRetryAfter(clientId) {
|
|
302
|
+
return this.tracker[clientId]?.retryAfter;
|
|
303
|
+
}
|
|
304
|
+
clearExpiredLimits() {
|
|
305
|
+
const now = Date.now();
|
|
306
|
+
Object.keys(this.tracker).forEach((clientId) => {
|
|
307
|
+
const limitInfo = this.tracker[clientId];
|
|
308
|
+
if (limitInfo.lastUpdated && now - limitInfo.lastUpdated > 3e5) delete this.tracker[clientId];
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
class ResilienceManager {
|
|
313
|
+
constructor(config2 = {}, clientId = "default") {
|
|
314
|
+
this.config = {
|
|
315
|
+
fallbackEnabled: config2.fallbackEnabled ?? false,
|
|
316
|
+
retryAttempts: Math.max(0, config2.retryAttempts ?? 2),
|
|
317
|
+
// Number of additional retries
|
|
318
|
+
retryDelay: Math.max(0, config2.retryDelay ?? 1e3)
|
|
319
|
+
};
|
|
320
|
+
this.clientId = clientId;
|
|
321
|
+
this.rateLimitManager = RateLimitManager.getInstance();
|
|
322
|
+
}
|
|
323
|
+
async executeWithResilience(axiosClient, requestConfig, fallbackData) {
|
|
324
|
+
let lastError;
|
|
325
|
+
const totalAttempts = 1 + this.config.retryAttempts;
|
|
326
|
+
this.rateLimitManager.clearExpiredLimits();
|
|
327
|
+
if (this.rateLimitManager.isRateLimited(this.clientId)) {
|
|
328
|
+
const retryAfter = this.rateLimitManager.getRetryAfter(this.clientId);
|
|
329
|
+
if (retryAfter) {
|
|
330
|
+
console.warn(`[Dymo API] Client ${this.clientId} is rate limited. Waiting ${retryAfter} seconds...`);
|
|
331
|
+
await this.sleep(retryAfter * 1e3);
|
|
332
|
+
}
|
|
325
333
|
}
|
|
326
|
-
;
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
334
|
+
for (let attempt = 1; attempt <= totalAttempts; attempt++) {
|
|
335
|
+
try {
|
|
336
|
+
const response = await axiosClient.request(requestConfig);
|
|
337
|
+
this.rateLimitManager.updateRateLimit(this.clientId, response.headers);
|
|
338
|
+
if (response.status === 429) {
|
|
339
|
+
const retryAfter = this.rateLimitManager.getRetryAfter(this.clientId);
|
|
340
|
+
if (retryAfter) {
|
|
341
|
+
console.warn(`[Dymo API] Rate limited. Waiting ${retryAfter} seconds (no retries)`);
|
|
342
|
+
await this.sleep(retryAfter * 1e3);
|
|
343
|
+
}
|
|
344
|
+
throw new Error(`Rate limited (429) - not retrying`);
|
|
345
|
+
}
|
|
346
|
+
return response.data;
|
|
347
|
+
} catch (error) {
|
|
348
|
+
lastError = error;
|
|
349
|
+
let shouldRetry = this.shouldRetry(error);
|
|
350
|
+
const isLastAttempt = attempt === totalAttempts;
|
|
351
|
+
if (error.response?.status === 429) shouldRetry = false;
|
|
352
|
+
if (!shouldRetry || isLastAttempt) {
|
|
353
|
+
if (this.config.fallbackEnabled && fallbackData) {
|
|
354
|
+
console.warn(`[Dymo API] Request failed after ${attempt} attempts. Using fallback data.`);
|
|
355
|
+
return fallbackData;
|
|
356
|
+
}
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
359
|
+
const delay = this.config.retryDelay * Math.pow(2, attempt - 1);
|
|
360
|
+
console.warn(`[Dymo API] Attempt ${attempt} failed. Retrying in ${delay}ms...`);
|
|
361
|
+
await this.sleep(delay);
|
|
362
|
+
}
|
|
344
363
|
}
|
|
345
|
-
;
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
364
|
+
throw lastError;
|
|
365
|
+
}
|
|
366
|
+
shouldRetry(error) {
|
|
367
|
+
const statusCode = error.response?.status;
|
|
368
|
+
const isNetworkError = !error.response && error.code !== "ECONNABORTED";
|
|
369
|
+
const isServerError = statusCode && statusCode >= 500;
|
|
370
|
+
return isNetworkError || isServerError;
|
|
371
|
+
}
|
|
372
|
+
sleep(ms) {
|
|
373
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
374
|
+
}
|
|
375
|
+
getConfig() {
|
|
376
|
+
return { ...this.config };
|
|
377
|
+
}
|
|
378
|
+
getClientId() {
|
|
379
|
+
return this.clientId;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
class FallbackDataGenerator {
|
|
383
|
+
static generateFallbackData(method, inputData) {
|
|
384
|
+
switch (method) {
|
|
385
|
+
case "isValidData":
|
|
386
|
+
return this.generateDataValidationAnalysis(inputData);
|
|
387
|
+
case "isValidEmail":
|
|
388
|
+
return this.generateEmailValidatorResponse(inputData);
|
|
389
|
+
case "isValidIP":
|
|
390
|
+
return this.generateIPValidatorResponse(inputData);
|
|
391
|
+
case "isValidPhone":
|
|
392
|
+
return this.generatePhoneValidatorResponse(inputData);
|
|
393
|
+
case "protectReq":
|
|
394
|
+
return this.generateHTTPRequest(inputData);
|
|
395
|
+
case "sendEmail":
|
|
396
|
+
return this.generateEmailStatus();
|
|
397
|
+
case "getRandom":
|
|
398
|
+
return this.generateSRNSummary(inputData);
|
|
399
|
+
case "extractWithTextly":
|
|
400
|
+
return this.generateExtractWithTextly(inputData);
|
|
401
|
+
case "getPrayerTimes":
|
|
402
|
+
return this.generatePrayerTimes(inputData);
|
|
403
|
+
case "satinize":
|
|
404
|
+
return this.generateSatinizedInputAnalysis(inputData);
|
|
405
|
+
case "isValidPwd":
|
|
406
|
+
return this.generatePasswordValidationResult(inputData);
|
|
407
|
+
default:
|
|
408
|
+
throw new Error(`Unknown method for fallback: ${method}`);
|
|
360
409
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
410
|
+
}
|
|
411
|
+
static validateURL(url) {
|
|
412
|
+
if (!url) return false;
|
|
413
|
+
const urlRegex = /^https?:\/\/(?:[-\w.])+(?:\:[0-9]+)?(?:\/(?:[\w\/_.])*(?:\?(?:[\w&=%.])*)?(?:\#(?:[\w.])*)?)?$/;
|
|
414
|
+
return urlRegex.test(url);
|
|
415
|
+
}
|
|
416
|
+
static validateEmail(email) {
|
|
417
|
+
if (!email) return false;
|
|
418
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
419
|
+
return emailRegex.test(email);
|
|
420
|
+
}
|
|
421
|
+
static validateDomain(domain) {
|
|
422
|
+
if (!domain) return false;
|
|
423
|
+
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])*$/;
|
|
424
|
+
if (!domainRegex.test(domain)) return false;
|
|
425
|
+
const parts = domain.split(".");
|
|
426
|
+
return parts.length >= 2 && parts[parts.length - 1].length > 0;
|
|
427
|
+
}
|
|
428
|
+
static validateCreditCard(creditCard) {
|
|
429
|
+
if (!creditCard) return false;
|
|
430
|
+
const cardNumber = typeof creditCard === "string" ? creditCard : creditCard?.pan || "";
|
|
431
|
+
if (!cardNumber) return false;
|
|
432
|
+
const cardRegex = /^\d{13,19}$/;
|
|
433
|
+
if (!cardRegex.test(cardNumber.replace(/\s/g, ""))) return false;
|
|
434
|
+
const digits = cardNumber.replace(/\s/g, "").split("").map(Number);
|
|
435
|
+
let sum = 0;
|
|
436
|
+
let isEven = false;
|
|
437
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
438
|
+
let digit = digits[i];
|
|
439
|
+
if (isEven) {
|
|
440
|
+
digit *= 2;
|
|
441
|
+
if (digit > 9) digit -= 9;
|
|
442
|
+
}
|
|
443
|
+
sum += digit;
|
|
444
|
+
isEven = !isEven;
|
|
375
445
|
}
|
|
376
|
-
;
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
446
|
+
return sum % 10 === 0;
|
|
447
|
+
}
|
|
448
|
+
static validateIP(ip) {
|
|
449
|
+
if (!ip) return false;
|
|
450
|
+
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]?)$/;
|
|
451
|
+
const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
452
|
+
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
|
453
|
+
}
|
|
454
|
+
static validatePhone(phone) {
|
|
455
|
+
if (!phone) return false;
|
|
456
|
+
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
|
|
457
|
+
return phoneRegex.test(phone.replace(/[^\d+]/g, ""));
|
|
458
|
+
}
|
|
459
|
+
static validateWallet(wallet) {
|
|
460
|
+
if (!wallet) return false;
|
|
461
|
+
const bitcoinRegex = /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/;
|
|
462
|
+
const ethereumRegex = /^0x[a-fA-F0-9]{40}$/;
|
|
463
|
+
return bitcoinRegex.test(wallet) || ethereumRegex.test(wallet);
|
|
464
|
+
}
|
|
465
|
+
static validateIBAN(iban) {
|
|
466
|
+
if (!iban) return false;
|
|
467
|
+
const ibanRegex = /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/;
|
|
468
|
+
return ibanRegex.test(iban.replace(/\s/g, "").toUpperCase());
|
|
469
|
+
}
|
|
470
|
+
static extractDomain(url) {
|
|
471
|
+
if (!url) return "";
|
|
472
|
+
try {
|
|
473
|
+
return new URL(url).hostname;
|
|
474
|
+
} catch {
|
|
475
|
+
return "";
|
|
404
476
|
}
|
|
405
|
-
|
|
477
|
+
}
|
|
478
|
+
static generateDataValidationAnalysis(inputData) {
|
|
479
|
+
return {
|
|
480
|
+
url: {
|
|
481
|
+
valid: this.validateURL(inputData?.url),
|
|
482
|
+
fraud: false,
|
|
483
|
+
freeSubdomain: false,
|
|
484
|
+
customTLD: false,
|
|
485
|
+
url: inputData?.url || "",
|
|
486
|
+
domain: this.extractDomain(inputData?.url),
|
|
487
|
+
plugins: {
|
|
488
|
+
blocklist: false,
|
|
489
|
+
compromiseDetector: false,
|
|
490
|
+
mxRecords: [],
|
|
491
|
+
nsfw: false,
|
|
492
|
+
reputation: "unknown",
|
|
493
|
+
riskScore: 0,
|
|
494
|
+
torNetwork: false,
|
|
495
|
+
typosquatting: 0,
|
|
496
|
+
urlShortener: false
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
email: this.generateEmailDataAnalysis(inputData?.email),
|
|
500
|
+
phone: this.generatePhoneDataAnalysis(inputData?.phone),
|
|
501
|
+
domain: {
|
|
502
|
+
valid: this.validateDomain(inputData?.domain),
|
|
503
|
+
fraud: false,
|
|
504
|
+
freeSubdomain: false,
|
|
505
|
+
customTLD: false,
|
|
506
|
+
domain: inputData?.domain || "",
|
|
507
|
+
plugins: {
|
|
508
|
+
blocklist: false,
|
|
509
|
+
compromiseDetector: false,
|
|
510
|
+
mxRecords: [],
|
|
511
|
+
nsfw: false,
|
|
512
|
+
reputation: "unknown",
|
|
513
|
+
riskScore: 0,
|
|
514
|
+
torNetwork: false,
|
|
515
|
+
typosquatting: 0,
|
|
516
|
+
urlShortener: false
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
creditCard: {
|
|
520
|
+
valid: this.validateCreditCard(inputData?.creditCard),
|
|
521
|
+
fraud: false,
|
|
522
|
+
test: false,
|
|
523
|
+
type: "unknown",
|
|
524
|
+
creditCard: typeof inputData?.creditCard === "string" ? inputData.creditCard : inputData?.creditCard?.pan || "",
|
|
525
|
+
plugins: {
|
|
526
|
+
blocklist: false,
|
|
527
|
+
riskScore: 0
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
ip: this.generateIPDataAnalysis(inputData?.ip),
|
|
531
|
+
wallet: {
|
|
532
|
+
valid: this.validateWallet(inputData?.wallet),
|
|
533
|
+
fraud: false,
|
|
534
|
+
wallet: inputData?.wallet || "",
|
|
535
|
+
type: "unknown",
|
|
536
|
+
plugins: {
|
|
537
|
+
blocklist: false,
|
|
538
|
+
riskScore: 0,
|
|
539
|
+
torNetwork: false
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
userAgent: {
|
|
543
|
+
valid: false,
|
|
544
|
+
fraud: false,
|
|
545
|
+
userAgent: inputData?.userAgent || "",
|
|
546
|
+
bot: true,
|
|
547
|
+
device: { type: "unknown", brand: "unknown" },
|
|
548
|
+
plugins: {
|
|
549
|
+
blocklist: false,
|
|
550
|
+
riskScore: 0
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
iban: {
|
|
554
|
+
valid: this.validateIBAN(inputData?.iban),
|
|
555
|
+
fraud: false,
|
|
556
|
+
iban: inputData?.iban || "",
|
|
557
|
+
plugins: {
|
|
558
|
+
blocklist: false,
|
|
559
|
+
riskScore: 0
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
static generateEmailValidatorResponse(inputData) {
|
|
565
|
+
return {
|
|
566
|
+
email: inputData?.email || "",
|
|
567
|
+
allow: this.validateEmail(inputData?.email),
|
|
568
|
+
reasons: this.validateEmail(inputData?.email) ? [] : ["INVALID"],
|
|
569
|
+
response: this.generateEmailDataAnalysis(inputData?.email)
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
static generateEmailDataAnalysis(email) {
|
|
573
|
+
return {
|
|
574
|
+
valid: this.validateEmail(email),
|
|
575
|
+
fraud: false,
|
|
576
|
+
proxiedEmail: false,
|
|
577
|
+
freeSubdomain: false,
|
|
578
|
+
corporate: false,
|
|
579
|
+
email: email || "",
|
|
580
|
+
realUser: "",
|
|
581
|
+
didYouMean: null,
|
|
582
|
+
noReply: false,
|
|
583
|
+
customTLD: false,
|
|
584
|
+
domain: "",
|
|
585
|
+
roleAccount: false,
|
|
586
|
+
plugins: {
|
|
587
|
+
mxRecords: [],
|
|
588
|
+
blocklist: false,
|
|
589
|
+
compromiseDetector: false,
|
|
590
|
+
nsfw: false,
|
|
591
|
+
reputation: "unknown",
|
|
592
|
+
riskScore: 0,
|
|
593
|
+
torNetwork: false,
|
|
594
|
+
typosquatting: 0,
|
|
595
|
+
urlShortener: false
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
static generateIPValidatorResponse(inputData) {
|
|
600
|
+
return {
|
|
601
|
+
ip: inputData?.ip || "",
|
|
602
|
+
allow: this.validateIP(inputData?.ip),
|
|
603
|
+
reasons: this.validateIP(inputData?.ip) ? [] : ["INVALID"],
|
|
604
|
+
response: this.generateIPDataAnalysis(inputData?.ip)
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
static generateIPDataAnalysis(ip) {
|
|
608
|
+
const isValid = this.validateIP(ip);
|
|
609
|
+
return {
|
|
610
|
+
valid: isValid,
|
|
611
|
+
type: isValid ? "IPv4" : "Invalid",
|
|
612
|
+
class: isValid ? "A" : "Unknown",
|
|
613
|
+
fraud: false,
|
|
614
|
+
ip: ip || "",
|
|
615
|
+
continent: "",
|
|
616
|
+
continentCode: "",
|
|
617
|
+
country: "",
|
|
618
|
+
countryCode: "",
|
|
619
|
+
region: "",
|
|
620
|
+
regionName: "",
|
|
621
|
+
city: "",
|
|
622
|
+
district: "",
|
|
623
|
+
zipCode: "",
|
|
624
|
+
lat: 0,
|
|
625
|
+
lon: 0,
|
|
626
|
+
timezone: "",
|
|
627
|
+
offset: 0,
|
|
628
|
+
currency: "",
|
|
629
|
+
isp: "",
|
|
630
|
+
org: "",
|
|
631
|
+
as: "",
|
|
632
|
+
asname: "",
|
|
633
|
+
mobile: false,
|
|
634
|
+
proxy: true,
|
|
635
|
+
hosting: false,
|
|
636
|
+
plugins: {
|
|
637
|
+
blocklist: false,
|
|
638
|
+
riskScore: 0
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
static generatePhoneValidatorResponse(inputData) {
|
|
643
|
+
return {
|
|
644
|
+
phone: inputData?.phone || "",
|
|
645
|
+
allow: this.validatePhone(inputData?.phone),
|
|
646
|
+
reasons: this.validatePhone(inputData?.phone) ? [] : ["INVALID"],
|
|
647
|
+
response: this.generatePhoneDataAnalysis(inputData?.phone)
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
static generatePhoneDataAnalysis(phone) {
|
|
651
|
+
const phoneNumber = phone?.phone || phone;
|
|
652
|
+
const isValid = this.validatePhone(phoneNumber);
|
|
653
|
+
return {
|
|
654
|
+
valid: isValid,
|
|
655
|
+
fraud: false,
|
|
656
|
+
phone: phone?.phone || "",
|
|
657
|
+
prefix: "",
|
|
658
|
+
number: "",
|
|
659
|
+
lineType: "Unknown",
|
|
660
|
+
carrierInfo: {
|
|
661
|
+
carrierName: "",
|
|
662
|
+
accuracy: 0,
|
|
663
|
+
carrierCountry: "",
|
|
664
|
+
carrierCountryCode: ""
|
|
665
|
+
},
|
|
666
|
+
country: "",
|
|
667
|
+
countryCode: "",
|
|
668
|
+
plugins: {
|
|
669
|
+
blocklist: false,
|
|
670
|
+
riskScore: 0
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
static generateHTTPRequest(inputData) {
|
|
675
|
+
return {
|
|
676
|
+
method: inputData?.method || "GET",
|
|
677
|
+
url: inputData?.url || "",
|
|
678
|
+
headers: inputData?.headers || {},
|
|
679
|
+
body: inputData?.body || null,
|
|
680
|
+
allow: false,
|
|
681
|
+
reasons: ["FRAUD"],
|
|
682
|
+
protected: true
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
static generateEmailStatus() {
|
|
686
|
+
return {
|
|
687
|
+
status: false,
|
|
688
|
+
error: "API unavailable - using fallback response"
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
static generateSRNSummary(inputData) {
|
|
692
|
+
const quantity = inputData?.quantity || 1;
|
|
693
|
+
const values = Array.from({ length: quantity }, () => ({
|
|
694
|
+
integer: 0,
|
|
695
|
+
float: 0
|
|
696
|
+
}));
|
|
697
|
+
return {
|
|
698
|
+
values,
|
|
699
|
+
executionTime: 0
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
static generateExtractWithTextly(inputData) {
|
|
703
|
+
return {
|
|
704
|
+
data: inputData?.data || "",
|
|
705
|
+
extracted: {},
|
|
706
|
+
error: "API unavailable - using fallback response"
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
static generatePrayerTimes(inputData) {
|
|
710
|
+
return {
|
|
711
|
+
error: "API unavailable - using fallback response"
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
static generateSatinizedInputAnalysis(inputData) {
|
|
715
|
+
return {
|
|
716
|
+
input: inputData?.input || "",
|
|
717
|
+
formats: {
|
|
718
|
+
ascii: false,
|
|
719
|
+
bitcoinAddress: false,
|
|
720
|
+
cLikeIdentifier: false,
|
|
721
|
+
coordinates: false,
|
|
722
|
+
crediCard: false,
|
|
723
|
+
date: false,
|
|
724
|
+
discordUsername: false,
|
|
725
|
+
doi: false,
|
|
726
|
+
domain: false,
|
|
727
|
+
e164Phone: false,
|
|
728
|
+
email: false,
|
|
729
|
+
emoji: false,
|
|
730
|
+
hanUnification: false,
|
|
731
|
+
hashtag: false,
|
|
732
|
+
hyphenWordBreak: false,
|
|
733
|
+
ipv6: false,
|
|
734
|
+
ip: false,
|
|
735
|
+
jiraTicket: false,
|
|
736
|
+
macAddress: false,
|
|
737
|
+
name: false,
|
|
738
|
+
number: false,
|
|
739
|
+
panFromGstin: false,
|
|
740
|
+
password: false,
|
|
741
|
+
port: false,
|
|
742
|
+
tel: false,
|
|
743
|
+
text: false,
|
|
744
|
+
semver: false,
|
|
745
|
+
ssn: false,
|
|
746
|
+
uuid: false,
|
|
747
|
+
url: false,
|
|
748
|
+
urlSlug: false,
|
|
749
|
+
username: false
|
|
750
|
+
},
|
|
751
|
+
includes: {
|
|
752
|
+
spaces: false,
|
|
753
|
+
hasSql: false,
|
|
754
|
+
hasNoSql: false,
|
|
755
|
+
letters: false,
|
|
756
|
+
uppercase: false,
|
|
757
|
+
lowercase: false,
|
|
758
|
+
symbols: false,
|
|
759
|
+
digits: false
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
static generatePasswordValidationResult(inputData) {
|
|
764
|
+
return {
|
|
765
|
+
valid: false,
|
|
766
|
+
password: inputData?.password || "",
|
|
767
|
+
details: [
|
|
768
|
+
{
|
|
769
|
+
validation: "length",
|
|
770
|
+
message: "API unavailable - using fallback response"
|
|
771
|
+
}
|
|
772
|
+
]
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
class DymoAPI {
|
|
777
|
+
/**
|
|
778
|
+
* @param {Object} options - Options to create the DymoAPI instance.
|
|
779
|
+
* @param {string} [options.rootApiKey] - The root API key.
|
|
780
|
+
* @param {string} [options.apiKey] - The API key.
|
|
781
|
+
* @param {string} [options.baseUrl] - Whether to use a local server instead of the cloud server.
|
|
782
|
+
* @param {Object} [options.serverEmailConfig] - The server email config.
|
|
783
|
+
* @param {Object} [options.rules] - The rules.
|
|
784
|
+
* @param {Object} [options.resilience] - The resilience config.
|
|
785
|
+
* @description
|
|
786
|
+
* This is the main class to interact with the Dymo API. It should be
|
|
787
|
+
* instantiated with the root API key and the API key. The root API key is
|
|
788
|
+
* used to fetch the tokens and the API key is used to authenticate the
|
|
789
|
+
* requests. Requests are retried once by default with exponential backoff.
|
|
790
|
+
* @example
|
|
791
|
+
* const dymoApi = new DymoAPI({
|
|
792
|
+
* rootApiKey: "6bfb7675-6b69-4f8d-9f43-5a6f7f02c6c5",
|
|
793
|
+
* apiKey: "dm_4c8b7675-6b69-4f8d-9f43-5a6f7f02c6c5"
|
|
794
|
+
* });
|
|
795
|
+
*/
|
|
796
|
+
constructor({
|
|
797
|
+
rootApiKey = null,
|
|
798
|
+
apiKey = null,
|
|
799
|
+
baseUrl = "https://api.tpeoficial.com",
|
|
800
|
+
serverEmailConfig = void 0,
|
|
801
|
+
rules = {},
|
|
802
|
+
resilience = {}
|
|
803
|
+
} = {}) {
|
|
804
|
+
this.rules = {
|
|
805
|
+
email: { mode: "LIVE", deny: ["FRAUD", "INVALID", "NO_MX_RECORDS", "NO_REPLY_EMAIL"] },
|
|
806
|
+
ip: { mode: "LIVE", deny: ["FRAUD", "INVALID", "TOR_NETWORK"] },
|
|
807
|
+
phone: { mode: "LIVE", deny: ["FRAUD", "INVALID"] },
|
|
808
|
+
sensitiveInfo: { mode: "LIVE", deny: ["EMAIL", "PHONE", "CREDIT_CARD"] },
|
|
809
|
+
waf: { mode: "LIVE", allowBots: ["CURL", "CATEGORY:SEARCH_ENGINE", "CATEGORY:PREVIEW"], deny: ["FRAUD", "TOR_NETWORK"] },
|
|
810
|
+
...rules
|
|
811
|
+
};
|
|
812
|
+
this.rootApiKey = rootApiKey;
|
|
813
|
+
this.apiKey = apiKey;
|
|
814
|
+
this.serverEmailConfig = serverEmailConfig;
|
|
815
|
+
this.baseUrl = baseUrl;
|
|
816
|
+
const clientId = this.apiKey || this.rootApiKey || "anonymous";
|
|
817
|
+
this.resilienceManager = new ResilienceManager(resilience, clientId);
|
|
818
|
+
this.axiosClient = axios.create({
|
|
819
|
+
baseURL: `${validBaseURL(this.baseUrl)}/v1`,
|
|
820
|
+
headers: {
|
|
821
|
+
"User-Agent": "DymoAPISDK/1.0.0",
|
|
822
|
+
"X-Dymo-SDK-Env": "Node",
|
|
823
|
+
"X-Dymo-SDK-Version": "1.2.33"
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
if (this.rootApiKey || this.apiKey) this.axiosClient.defaults.headers.Authorization = `Bearer ${this.rootApiKey || this.apiKey}`;
|
|
827
|
+
}
|
|
828
|
+
getEmailPlugins(rules) {
|
|
829
|
+
return [
|
|
830
|
+
rules.deny.includes("NO_MX_RECORDS") ? "mxRecords" : void 0,
|
|
831
|
+
rules.deny.includes("NO_REACHABLE") ? "reachable" : void 0,
|
|
832
|
+
rules.deny.includes("HIGH_RISK_SCORE") ? "riskScore" : void 0,
|
|
833
|
+
rules.deny.includes("NO_GRAVATAR") ? "gravatar" : void 0
|
|
834
|
+
].filter(Boolean);
|
|
835
|
+
}
|
|
836
|
+
// FUNCTIONS / Private.
|
|
837
|
+
/**
|
|
838
|
+
* Validates the given data against the configured validation settings.
|
|
839
|
+
*
|
|
840
|
+
* This method requires either the root API key or the API key to be set.
|
|
841
|
+
* If neither is set, it will throw an error.
|
|
842
|
+
*
|
|
843
|
+
* @deprecated Use `isValidDataRaw` instead. This feature will be modified soon.
|
|
844
|
+
* @param {Object} data - The data to be validated.
|
|
845
|
+
* @param {string} [data.url] - Optional URL to be validated.
|
|
846
|
+
* @param {string} [data.email] - Optional email address to be validated.
|
|
847
|
+
* @param {Interfaces.PhoneData} [data.phone] - Optional phone number data to be validated.
|
|
848
|
+
* @param {string} [data.domain] - Optional domain name to be validated.
|
|
849
|
+
* @param {string|Interfaces.CreditCardData} [data.creditCard] - Optional credit card number or data to be validated.
|
|
850
|
+
* @param {string} [data.ip] - Optional IP address to be validated.
|
|
851
|
+
* @param {string} [data.wallet] - Optional wallet address to be validated.
|
|
852
|
+
* @param {string} [data.userAgent] - Optional user agent string to be validated.
|
|
853
|
+
* @param {string} [data.iban] - Optional IBAN to be validated.
|
|
854
|
+
* @param {Interfaces.VerifyPlugins[]} [data.plugins] - Optional array of verification plugins to be used.
|
|
855
|
+
* @returns {Promise<Interfaces.DataValidationAnalysis>} A promise that resolves to the response from the server.
|
|
856
|
+
* @throws Will throw an error if there is an issue with the validation process.
|
|
857
|
+
*
|
|
858
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier)
|
|
859
|
+
*/
|
|
860
|
+
async isValidData(data) {
|
|
861
|
+
const fallbackData = FallbackDataGenerator.generateFallbackData("isValidData", data);
|
|
862
|
+
return await this.resilienceManager.executeWithResilience(
|
|
863
|
+
this.axiosClient,
|
|
864
|
+
{
|
|
865
|
+
method: "POST",
|
|
866
|
+
url: "/private/secure/verify",
|
|
867
|
+
data
|
|
868
|
+
},
|
|
869
|
+
this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : void 0
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Validates the given data against the configured validation settings.
|
|
874
|
+
*
|
|
875
|
+
* This method requires either the root API key or the API key to be set.
|
|
876
|
+
* If neither is set, it will throw an error.
|
|
877
|
+
*
|
|
878
|
+
* @param {Object} data - The data to be validated.
|
|
879
|
+
* @param {string} [data.url] - Optional URL to be validated.
|
|
880
|
+
* @param {string} [data.email] - Optional email address to be validated.
|
|
881
|
+
* @param {Interfaces.PhoneData} [data.phone] - Optional phone number data to be validated.
|
|
882
|
+
* @param {string} [data.domain] - Optional domain name to be validated.
|
|
883
|
+
* @param {string|Interfaces.CreditCardData} [data.creditCard] - Optional credit card number or data to be validated.
|
|
884
|
+
* @param {string} [data.ip] - Optional IP address to be validated.
|
|
885
|
+
* @param {string} [data.wallet] - Optional wallet address to be validated.
|
|
886
|
+
* @param {string} [data.userAgent] - Optional user agent string to be validated.
|
|
887
|
+
* @param {string} [data.iban] - Optional IBAN to be validated.
|
|
888
|
+
* @param {Interfaces.VerifyPlugins[]} [data.plugins] - Optional array of verification plugins to be used.
|
|
889
|
+
* @returns {Promise<Interfaces.DataValidationAnalysis>} A promise that resolves to the response from the server.
|
|
890
|
+
* @throws Will throw an error if there is an issue with the validation process.
|
|
891
|
+
*
|
|
892
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier)
|
|
893
|
+
*/
|
|
894
|
+
async isValidDataRaw(data) {
|
|
895
|
+
const fallbackData = FallbackDataGenerator.generateFallbackData("isValidDataRaw", data);
|
|
896
|
+
return await this.resilienceManager.executeWithResilience(
|
|
897
|
+
this.axiosClient,
|
|
898
|
+
{
|
|
899
|
+
method: "POST",
|
|
900
|
+
url: "/private/secure/verify",
|
|
901
|
+
data
|
|
902
|
+
},
|
|
903
|
+
this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : void 0
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Validates the given email against the configured rules.
|
|
908
|
+
*
|
|
909
|
+
* This method requires either the root API key or the API key to be set.
|
|
910
|
+
* If neither is set, it will throw an error.
|
|
911
|
+
*
|
|
912
|
+
* @param {string} [email] - Email address to validate.
|
|
913
|
+
* @param {NegativeEmailRules[]} [rules] - Optional rules for validation. Some rules are premium features.
|
|
914
|
+
* @important
|
|
915
|
+
* **⚠️ NO_MX_RECORDS, HIGH_RISK_SCORE and NO_REACHABLE are [PREMIUM](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier) features.**
|
|
916
|
+
* @returns {Promise<Interfaces.EmailValidatorResponse>} Resolves with the validation response.
|
|
917
|
+
* @throws Will throw an error if validation cannot be performed.
|
|
918
|
+
*
|
|
919
|
+
* @example
|
|
920
|
+
* const valid = await dymoClient.isValidEmail("user@example.com", { deny: ["FRAUD", "NO_MX_RECORDS"] });
|
|
921
|
+
*
|
|
922
|
+
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/email-validation)
|
|
923
|
+
*/
|
|
924
|
+
async isValidEmail(email, rules = this.rules.email) {
|
|
925
|
+
const fallbackData = FallbackDataGenerator.generateFallbackData("isValidEmail", email);
|
|
926
|
+
return await this.resilienceManager.executeWithResilience(
|
|
927
|
+
this.axiosClient,
|
|
928
|
+
{
|
|
929
|
+
method: "POST",
|
|
930
|
+
url: "/private/secure/verify",
|
|
931
|
+
data: { email, plugins: this.getEmailPlugins(rules) }
|
|
932
|
+
},
|
|
933
|
+
this.resilienceManager.getConfig().fallbackEnabled ? fallbackData : void 0
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Validates the given IP against the configured rules.
|
|
938
|
+
*
|
|
939
|
+
* This method requires either the root API key or the API key to be set.
|
|
940
|
+
* If neither is set, it will throw an error.
|
|
941
|
+
*
|
|
942
|
+
* @param {string} [ip] - IP address to validate.
|
|
943
|
+
* @param {NegativeEmailRules[]} [rules] - Optional rules for validation. Some rules are premium features.
|
|
944
|
+
* @important
|
|
945
|
+
* **⚠️ TOR_NETWORK and HIGH_RISK_SCORE are [PREMIUM](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier) features.**
|
|
946
|
+
* @returns {Promise<Interfaces.IPValidatorResponse>} Resolves with the validation response.
|
|
947
|
+
* @throws Will throw an error if validation cannot be performed.
|
|
948
|
+
*
|
|
949
|
+
* @example
|
|
950
|
+
* const valid = await isValidIP("52.94.236.248", { deny: ["FRAUD", "TOR_NETWORK", "COUNTRY:RU"] });
|
|
951
|
+
*
|
|
952
|
+
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/ip-validation)
|
|
953
|
+
*/
|
|
954
|
+
async isValidIP(ip, rules = this.rules.ip) {
|
|
955
|
+
return await isValidIP(this.axiosClient, ip, rules);
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Validates the given email against the configured rules.
|
|
959
|
+
*
|
|
960
|
+
* This method requires either the root API key or the API key to be set.
|
|
961
|
+
* If neither is set, it will throw an error.
|
|
962
|
+
*
|
|
963
|
+
* @param {string} [phone] - Phone number to validate.
|
|
964
|
+
* @param {NegativePhoneRules[]} [rules] - Optional rules for validation. Some rules are premium features.
|
|
965
|
+
* @important
|
|
966
|
+
* **⚠️ HIGH_RISK_SCORE is a [PREMIUM](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier) feature.**
|
|
967
|
+
* @returns {Promise<Interfaces.EmailValidatorResponse>} Resolves with the validation response.
|
|
968
|
+
* @throws Will throw an error if validation cannot be performed.
|
|
969
|
+
*
|
|
970
|
+
* @example
|
|
971
|
+
* const valid = await dymoClient.isValidPhone("+34617509462", { deny: ["FRAUD", "INVALID"] });
|
|
972
|
+
*
|
|
973
|
+
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/phone-validation)
|
|
974
|
+
*/
|
|
975
|
+
async isValidPhone(phone, rules = this.rules.phone) {
|
|
976
|
+
return await isValidPhone(this.axiosClient, phone, rules);
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Protects the given request against the configured rules.
|
|
980
|
+
*
|
|
981
|
+
* This method requires either the root API key or the API key to be set.
|
|
982
|
+
* If neither is set, it will throw an error.
|
|
983
|
+
*
|
|
984
|
+
* @param {Object} req - The request object to be protected.
|
|
985
|
+
* @param {Interfaces.WafRules} [rules] - Optional rules for protection. Some rules are premium features.
|
|
986
|
+
* @returns {Promise<Interfaces.HTTPRequest>} Resolves with the protected request.
|
|
987
|
+
* @important
|
|
988
|
+
* **⚠️ This is a [PREMIUM](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier) and BETA feature.**
|
|
989
|
+
* @throws Will throw an error if protection cannot be performed.
|
|
990
|
+
*
|
|
991
|
+
* @example
|
|
992
|
+
* const protectedReq = await dymoClient.protectReq(req);
|
|
993
|
+
*
|
|
994
|
+
* @see [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/data-verifier)
|
|
995
|
+
*/
|
|
996
|
+
async protectReq(req, rules = this.rules.waf) {
|
|
997
|
+
return await protectReq(this.axiosClient, req, rules);
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Sends an email using the configured email client settings.
|
|
1001
|
+
*
|
|
1002
|
+
* This method requires either the root API key or the server email config to be set.
|
|
1003
|
+
* If neither is set, it will throw an error.
|
|
1004
|
+
*
|
|
1005
|
+
* @param {Object} data - The email data to be sent.
|
|
1006
|
+
* @param {string} data.from - The email address from which the email will be sent.
|
|
1007
|
+
* @param {string} data.to - The email address to which the email will be sent.
|
|
1008
|
+
* @param {string} data.subject - The subject of the email.
|
|
1009
|
+
* @param {string} [data.html] - The HTML content of the email.
|
|
1010
|
+
* @param {React.ReactElement} [data.react] - The React component to be rendered as the email content.
|
|
1011
|
+
* @param {Object} [data.options] - Content configuration options.
|
|
1012
|
+
* @param {"high" | "normal" | "low" | undefined} [data.options.priority="normal"] - Email priority (default: normal).
|
|
1013
|
+
* @param {boolean} [data.options.waitToResponse=true] - Wait until the email is sent (default: true).
|
|
1014
|
+
* @param {boolean} [data.options.composeTailwindClasses] - Whether to compose tailwind classes.
|
|
1015
|
+
* @param {Attachment[]} [data.attachments] - An array of attachments to be included in the email.
|
|
1016
|
+
* @param {string} data.attachments[].filename - The name of the attached file.
|
|
1017
|
+
* @param {string} [data.attachments[].path] - The path or URL of the attached file. Either this or `content` must be provided.
|
|
1018
|
+
* @param {Buffer} [data.attachments[].content] - The content of the attached file as a Buffer. Either this or `path` must be provided.
|
|
1019
|
+
* @param {string} [data.attachments[].cid] - The CID (Content-ID) of the attached file, used for inline images.
|
|
1020
|
+
* @returns {Promise<Interfaces.EmailStatus>} A promise that resolves to the response from the server.
|
|
1021
|
+
* @throws Will throw an error if there is an issue with the email sending process.
|
|
1022
|
+
*
|
|
1023
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/sender-send-email/getting-started)
|
|
1024
|
+
*/
|
|
1025
|
+
async sendEmail(data) {
|
|
1026
|
+
if (!this.serverEmailConfig && !this.rootApiKey) console.error(`[${config.lib.name}] You must configure the email client settings.`);
|
|
1027
|
+
return await sendEmail(this.axiosClient, { serverEmailConfig: this.serverEmailConfig, ...data });
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Generates a random number between the provided min and max values.
|
|
1031
|
+
*
|
|
1032
|
+
* This method requires either the root API key or the API key to be set.
|
|
1033
|
+
* If neither is set, it will throw an error.
|
|
1034
|
+
*
|
|
1035
|
+
* @param {Interfaces.SRNG} data - The data to be sent.
|
|
1036
|
+
* @param {number} data.min - The minimum value of the range.
|
|
1037
|
+
* @param {number} data.max - The maximum value of the range.
|
|
1038
|
+
* @param {number} [data.quantity] - The number of random values to generate. Defaults to 1 if not provided.
|
|
1039
|
+
* @returns {Promise<Interfaces.SRNSummary>} A promise that resolves to the response from the server.
|
|
1040
|
+
* @throws Will throw an error if there is an issue with the random number generation process.
|
|
1041
|
+
*
|
|
1042
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/secure-random-number-generator)
|
|
1043
|
+
*/
|
|
1044
|
+
async getRandom(data) {
|
|
1045
|
+
return await getRandom(this.axiosClient, data);
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Extracts structured data from a given string using Textly.
|
|
1049
|
+
*
|
|
1050
|
+
* This method requires either the root API key or the API key to be set.
|
|
1051
|
+
* If neither is set, it will throw an error.
|
|
1052
|
+
*
|
|
1053
|
+
* @param {Interfaces.ExtractWithTextly} data - The data to be sent, containing the string to be processed and the format schema.
|
|
1054
|
+
* @returns {Promise<any>} A promise that resolves to the extracted structured data.
|
|
1055
|
+
* @throws Will throw an error if there is an issue with the extraction process.
|
|
1056
|
+
*
|
|
1057
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/private/textly/text-extraction)
|
|
1058
|
+
*/
|
|
1059
|
+
async extractWithTextly(data) {
|
|
1060
|
+
return await extractWithTextly(this.axiosClient, data);
|
|
1061
|
+
}
|
|
1062
|
+
// FUNCTIONS / Public.
|
|
1063
|
+
/**
|
|
1064
|
+
* Retrieves the prayer times for the given location.
|
|
1065
|
+
*
|
|
1066
|
+
* This method requires a latitude and longitude to be provided in the
|
|
1067
|
+
* data object. If either of these are not provided, it will throw an error.
|
|
1068
|
+
*
|
|
1069
|
+
* @param {Object} data - The data to be sent.
|
|
1070
|
+
* @param {number} data.lat - The latitude of the location.
|
|
1071
|
+
* @param {number} data.lon - The longitude of the location.
|
|
1072
|
+
* @returns {Promise<Interfaces.CountryPrayerTimes | { error: string }>} A promise that resolves to the response from the server.
|
|
1073
|
+
* @throws Will throw an error if there is an issue with the prayer times retrieval process.
|
|
1074
|
+
*
|
|
1075
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/public/prayertimes)
|
|
1076
|
+
*/
|
|
1077
|
+
async getPrayerTimes(data) {
|
|
1078
|
+
return await getPrayerTimes(this.axiosClient, data);
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Satinizes the input, replacing any special characters with their HTML
|
|
1082
|
+
* entities.
|
|
1083
|
+
*
|
|
1084
|
+
* @deprecated Use `satinize` instead. This feature will be removed soon.
|
|
1085
|
+
* @param {Object} data - The data to be sent.
|
|
1086
|
+
* @param {string} data.input - The input to be satinized.
|
|
1087
|
+
* @returns {Promise<Interfaces.SatinizedInputAnalysis>} A promise that resolves to the response from the server.
|
|
1088
|
+
* @throws Will throw an error if there is an issue with the satinization process.
|
|
1089
|
+
*
|
|
1090
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/public/input-satinizer)
|
|
1091
|
+
*/
|
|
1092
|
+
async satinizer(data) {
|
|
1093
|
+
return await satinize(this.axiosClient, data.input);
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Satinizes the input, replacing any special characters with their HTML
|
|
1097
|
+
* entities.
|
|
1098
|
+
*
|
|
1099
|
+
* @param {Object} data - The data to be sent.
|
|
1100
|
+
* @param {string} data.input - The input to be satinized.
|
|
1101
|
+
* @returns {Promise<Interfaces.SatinizedInputAnalysis>} A promise that resolves to the response from the server.
|
|
1102
|
+
* @throws Will throw an error if there is an issue with the satinization process.
|
|
1103
|
+
*
|
|
1104
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/public/input-satinizer)
|
|
1105
|
+
*/
|
|
1106
|
+
async satinize(input) {
|
|
1107
|
+
return await satinize(this.axiosClient, input);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Validates a password based on the given parameters.
|
|
1111
|
+
*
|
|
1112
|
+
* This method requires the password to be provided in the data object.
|
|
1113
|
+
* If the password is not provided, it will throw an error. The method
|
|
1114
|
+
* will validate the password against the following rules:
|
|
1115
|
+
* - The password must be at least 8 characters long.
|
|
1116
|
+
* - The password must be at most 32 characters long.
|
|
1117
|
+
* - The password must contain at least one uppercase letter.
|
|
1118
|
+
* - The password must contain at least one lowercase letter.
|
|
1119
|
+
* - The password must contain at least one number.
|
|
1120
|
+
* - The password must contain at least one special character.
|
|
1121
|
+
* - The password must not contain any of the given banned words.
|
|
1122
|
+
*
|
|
1123
|
+
* @param {Object} data - The data to be sent.
|
|
1124
|
+
* @param {number} [data.min] - Minimum length of the password. Defaults to 8 if not provided.
|
|
1125
|
+
* @param {number} [data.max] - Maximum length of the password. Defaults to 32 if not provided.
|
|
1126
|
+
* @param {string} [data.email] - Optional email associated with the password.
|
|
1127
|
+
* @param {string} data.password - The password to be validated.
|
|
1128
|
+
* @param {string | string[]} [data.bannedWords] - The list of banned words that the password must not contain.
|
|
1129
|
+
* @returns {Promise<Interfaces.PasswordValidationResult>} A promise that resolves to the response from the server.
|
|
1130
|
+
* @throws Will throw an error if there is an issue with the password validation process.
|
|
1131
|
+
*
|
|
1132
|
+
* [Documentation](https://docs.tpeoficial.com/docs/dymo-api/public/password-validator)
|
|
1133
|
+
*/
|
|
1134
|
+
async isValidPwd(data) {
|
|
1135
|
+
return await isValidPwd(this.axiosClient, data);
|
|
1136
|
+
}
|
|
406
1137
|
}
|
|
407
|
-
;
|
|
408
|
-
exports.default = DymoAPI;
|
|
1138
|
+
module.exports = DymoAPI;
|