n8n-nodes-prestashop8 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,6 +30,7 @@ A comprehensive n8n community node for PrestaShop 8 integration with automatic X
30
30
  - ✅ **25+ resources supported**: products, customers, orders, stocks...
31
31
  - ✅ **Advanced filtering** with 10 search operators
32
32
  - ✅ **Raw mode** for debugging and advanced use cases
33
+ - ✅ **Retry on error** to automatically recover from transient failures (timeouts, connection drops)
33
34
 
34
35
  ## 🚀 Quick Start
35
36
 
@@ -137,6 +138,7 @@ npm install n8n-nodes-prestashop8
137
138
  - **Sorting**: `[price_ASC]`, `[date_add_DESC]`
138
139
  - **Fields**: `full`, `minimal`, or custom
139
140
  - **Debug**: URL, headers, timeout
141
+ - **Retry on error**: automatically retry a call that fails on a transient error — network timeout, connection drop, 5xx server error or 429 rate-limit (never on 4xx). Configurable max attempts and fixed delay between attempts; the retry budget is reset for each failing call. Each attempt is logged to the n8n server logs.
140
142
 
141
143
  ## 🎯 Usage Examples
142
144
 
@@ -169,7 +171,7 @@ Cron → PrestaShop 8 Node → Calculate KPIs → Email Report
169
171
  ### Common Problems
170
172
  - **401 Unauthorized** → Check API key and permissions
171
173
  - **404 Not Found** → Verify base URL and Webservices enabled
172
- - **Timeout** → Increase timeout in debug options
174
+ - **Timeout** → Increase timeout in debug options, or enable **Retry on error** to auto-recover from transient timeouts
173
175
 
174
176
  ### Get Help
175
177
  - 🐞 **[GitHub Issues](https://github.com/PPCM/n8n-nodes-prestashop8/issues)** - Bugs and questions
@@ -682,7 +682,7 @@ exports.PrestaShop8Description = {
682
682
  name: 'retryEnabled',
683
683
  type: 'boolean',
684
684
  default: false,
685
- description: 'Whether to retry a call that fails on a transient error (network timeout, connection drop, 5xx server error or 429 rate-limit). Never retries client errors (4xx).',
685
+ description: 'Whether to retry a call that fails on a transient error. Retries on: network timeout, connection drop (ECONNRESET / ECONNREFUSED / socket hang up), 5xx server errors and 429 rate-limit. Never retries client errors (4xx — invalid API key, 404, invalid XML). The retry budget is reset for each failing call.',
686
686
  },
687
687
  {
688
688
  displayName: 'Max Retries',
@@ -100,6 +100,12 @@ class PrestaShop8 {
100
100
  let requestDebugInfo = {};
101
101
  const opts = (0, http_1.getOperationOptions)(this, i);
102
102
  const { rawMode, timeout, neverError, includeResponseHeaders, showRequestInfo, showRequestUrl } = opts;
103
+ // Trace each retry attempt to the n8n server logs (Option A).
104
+ if (opts.retry.enabled) {
105
+ opts.retry.onRetry = (attempt, error) => {
106
+ this.logger.warn(`PrestaShop8: retry ${attempt}/${opts.retry.maxRetries} on ${resource}/${operation} after ${(0, http_1.describeError)(error)} — waiting ${opts.retry.retryDelay}ms`);
107
+ };
108
+ }
103
109
  // Throttle: pause before each PrestaShop call except the first.
104
110
  if (i > 0 && opts.delayBetweenCalls > 0) {
105
111
  await (0, http_1.sleep)(opts.delayBetweenCalls);
@@ -270,9 +276,12 @@ class PrestaShop8 {
270
276
  const filterValue = filter.value !== null && filter.value !== undefined ? String(filter.value).trim() : '';
271
277
  const format = http_1.FILTER_OPERATOR_FORMATS[filter.operator];
272
278
  if (format) {
273
- if (!format.requiresValue || filterValue) {
274
- filterParams[key] = format.template.replace('{v}', filterValue);
279
+ // Guard: operators that require a value must not be silently dropped
280
+ // when the value is empty, otherwise PrestaShop returns all records.
281
+ if (format.requiresValue && !filterValue) {
282
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Filter operator "${filter.operator}" on field "${filter.field}" requires a value. Use the "IS_EMPTY" operator to match empty fields.`);
275
283
  }
284
+ filterParams[key] = format.template.replace('{v}', filterValue);
276
285
  }
277
286
  else if (filterValue) {
278
287
  filterParams[key] = `[${filterValue}]`;
@@ -29,6 +29,8 @@ export interface RetryOptions {
29
29
  enabled: boolean;
30
30
  maxRetries: number;
31
31
  retryDelay: number;
32
+ /** Optional hook called before each retry wait, with the upcoming retry number (1-based) and the error. */
33
+ onRetry?: (attempt: number, error: any) => void;
32
34
  }
33
35
  /**
34
36
  * Pause execution for the given number of milliseconds (used to throttle calls).
@@ -40,6 +42,11 @@ export declare function sleep(ms: number): Promise<void>;
40
42
  * Never retries on 4xx (invalid key, not found, invalid XML, etc.).
41
43
  */
42
44
  export declare function isRetryableError(error: any): boolean;
45
+ /**
46
+ * Build a short human-readable reason from an error, for retry logging.
47
+ * Prefers the network code, then the HTTP status, then the message.
48
+ */
49
+ export declare function describeError(error: any): string;
43
50
  /**
44
51
  * Run an async HTTP operation with per-call retry on transient errors.
45
52
  * Each call gets its own retry budget; on the last attempt the error is rethrown
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FILTER_OPERATOR_FORMATS = void 0;
4
4
  exports.sleep = sleep;
5
5
  exports.isRetryableError = isRetryableError;
6
+ exports.describeError = describeError;
6
7
  exports.withRetry = withRetry;
7
8
  exports.getOperationOptions = getOperationOptions;
8
9
  exports.buildHttpOptions = buildHttpOptions;
@@ -69,12 +70,30 @@ function isRetryableError(error) {
69
70
  }
70
71
  return false;
71
72
  }
73
+ /**
74
+ * Build a short human-readable reason from an error, for retry logging.
75
+ * Prefers the network code, then the HTTP status, then the message.
76
+ */
77
+ function describeError(error) {
78
+ var _a, _b;
79
+ const code = (error === null || error === void 0 ? void 0 : error.code) || ((_a = error === null || error === void 0 ? void 0 : error.cause) === null || _a === void 0 ? void 0 : _a.code);
80
+ if (code) {
81
+ return code;
82
+ }
83
+ const status = (error === null || error === void 0 ? void 0 : error.httpCode) || ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.status);
84
+ if (status) {
85
+ return `HTTP ${status}`;
86
+ }
87
+ const message = error === null || error === void 0 ? void 0 : error.message;
88
+ return message ? String(message) : 'unknown error';
89
+ }
72
90
  /**
73
91
  * Run an async HTTP operation with per-call retry on transient errors.
74
92
  * Each call gets its own retry budget; on the last attempt the error is rethrown
75
93
  * so existing neverError / continueOnFail handling applies unchanged.
76
94
  */
77
95
  async function withRetry(retry, fn) {
96
+ var _a;
78
97
  const maxRetries = retry.enabled ? Math.max(0, retry.maxRetries) : 0;
79
98
  for (let attempt = 0;; attempt++) {
80
99
  try {
@@ -84,6 +103,8 @@ async function withRetry(retry, fn) {
84
103
  if (attempt >= maxRetries || !isRetryableError(error)) {
85
104
  throw error;
86
105
  }
106
+ // attempt is 0-based; report the upcoming retry number (1-based)
107
+ (_a = retry.onRetry) === null || _a === void 0 ? void 0 : _a.call(retry, attempt + 1, error);
87
108
  if (retry.retryDelay > 0) {
88
109
  await sleep(retry.retryDelay);
89
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-prestashop8",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Nœud n8n personnalisé pour PrestaShop 8 avec support CRUD complet et conversion XML/JSON automatique",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -86,7 +86,7 @@
86
86
  "brace-expansion": "^1.1.13",
87
87
  "uuid": "^14.0.0",
88
88
  "axios": "^1.16.0",
89
- "form-data": "^4.0.4",
89
+ "form-data": "^4.0.6",
90
90
  "follow-redirects": "^1.16.0"
91
91
  }
92
92
  }