@seranking/n8n-nodes-seranking 2.0.5 → 2.0.6
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.
|
@@ -153,7 +153,7 @@ async function AiSearchOperations(index) {
|
|
|
153
153
|
};
|
|
154
154
|
if (primaryBrand)
|
|
155
155
|
body.primary.brand = primaryBrand.trim();
|
|
156
|
-
return await apiRequest_1.apiRequest.call(this, 'POST', '/ai-search/overview/leaderboard', body, {}, index);
|
|
156
|
+
return await apiRequest_1.apiRequest.call(this, 'POST', '/ai-search/overview/leaderboard', body, {}, index, 180000, 2);
|
|
157
157
|
}
|
|
158
158
|
default:
|
|
159
159
|
throw new Error(`Unknown AI Search operation: ${operation}`);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
-
export declare function apiRequest(this: IExecuteFunctions, method: string, endpoint: string, body?: any, query?: any, itemIndex?: number): Promise<any>;
|
|
2
|
+
export declare function apiRequest(this: IExecuteFunctions, method: string, endpoint: string, body?: any, query?: any, itemIndex?: number, timeoutMs?: number, retryOn504?: number): Promise<any>;
|
|
@@ -6,8 +6,16 @@ const BASE_URL = 'https://api.seranking.com/v1';
|
|
|
6
6
|
const CREDENTIAL_TYPE = 'seRankingApi';
|
|
7
7
|
let lastRequestTime = 0;
|
|
8
8
|
const MIN_REQUEST_INTERVAL = 300;
|
|
9
|
-
|
|
10
|
-
var _a, _b, _c
|
|
9
|
+
function isGatewayTimeout(err) {
|
|
10
|
+
var _a, _b, _c;
|
|
11
|
+
const code = (_c = (_a = err === null || err === void 0 ? void 0 : err.statusCode) !== null && _a !== void 0 ? _a : (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : err === null || err === void 0 ? void 0 : err.httpCode;
|
|
12
|
+
if (code === 504 || code === '504')
|
|
13
|
+
return true;
|
|
14
|
+
const msg = String((err === null || err === void 0 ? void 0 : err.message) || '').toLowerCase();
|
|
15
|
+
return msg.includes('gateway tim') || msg.includes('504');
|
|
16
|
+
}
|
|
17
|
+
async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0, timeoutMs = 60000, retryOn504 = 0) {
|
|
18
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
11
19
|
const now = Date.now();
|
|
12
20
|
const timeSinceLastRequest = now - lastRequestTime;
|
|
13
21
|
if (timeSinceLastRequest < MIN_REQUEST_INTERVAL) {
|
|
@@ -18,7 +26,7 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
|
|
|
18
26
|
const httpMethod = method.toUpperCase();
|
|
19
27
|
const options = {
|
|
20
28
|
method: httpMethod,
|
|
21
|
-
timeout:
|
|
29
|
+
timeout: timeoutMs,
|
|
22
30
|
url: '',
|
|
23
31
|
};
|
|
24
32
|
if (query._fullUrl) {
|
|
@@ -102,8 +110,23 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
|
|
|
102
110
|
}
|
|
103
111
|
}
|
|
104
112
|
try {
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
let lastError;
|
|
114
|
+
for (let attempt = 0; attempt <= retryOn504; attempt++) {
|
|
115
|
+
if (attempt > 0) {
|
|
116
|
+
await (0, n8n_workflow_1.sleep)(2000 * attempt);
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
return await this.helpers.httpRequestWithAuthentication.call(this, CREDENTIAL_TYPE, options);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
lastError = err;
|
|
123
|
+
if (attempt < retryOn504 && isGatewayTimeout(err)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
throw lastError;
|
|
107
130
|
}
|
|
108
131
|
catch (error) {
|
|
109
132
|
if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('does not require credentials')) || ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes('No credentials'))) {
|
|
@@ -149,9 +172,12 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
|
|
|
149
172
|
errorMessage = 'Connection Failed';
|
|
150
173
|
errorDescription = 'Cannot reach SE Ranking API. Check your internet connection';
|
|
151
174
|
}
|
|
152
|
-
else if (error.code === 'ETIMEDOUT' ||
|
|
175
|
+
else if (error.code === 'ETIMEDOUT' ||
|
|
176
|
+
error.code === 'ECONNABORTED' ||
|
|
177
|
+
((_k = error.message) === null || _k === void 0 ? void 0 : _k.includes('timeout')) ||
|
|
178
|
+
((_l = error.message) === null || _l === void 0 ? void 0 : _l.includes('aborted'))) {
|
|
153
179
|
errorMessage = 'Request Timeout';
|
|
154
|
-
errorDescription =
|
|
180
|
+
errorDescription = `The request exceeded the node's ${Math.round(timeoutMs / 1000)}s timeout before SE Ranking responded (the API was reached, not offline). Heavy endpoints such as Get AI Search Leaderboard compute on demand and can take longer the first time a domain is queried; the result is cached afterward. Retry in a moment — a previously-computed domain returns almost instantly. You can also reduce the number of competitors/engines.`;
|
|
155
181
|
}
|
|
156
182
|
else {
|
|
157
183
|
errorMessage = (errorData === null || errorData === void 0 ? void 0 : errorData.message) || (errorData === null || errorData === void 0 ? void 0 : errorData.error) || error.message || 'Request failed';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seranking/n8n-nodes-seranking",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "n8n community node for SE Ranking's unified API — 194 operations across 21 resources: AI Search, Backlinks, Domain Analysis, Keyword Research, SERP Classic, Website Audits, Project Management, Competitors, Backlink Checker, Sub-Accounts, and more",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/seranking/n8n-nodes-seranking",
|