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