@contentstack/datasync-manager 2.4.0-beta.0 → 2.4.0-beta.1
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/api.js +33 -15
- package/dist/core/index.js +8 -14
- package/dist/plugins/helper.js +3 -1
- package/dist/util/messages.js +2 -0
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -56,7 +56,7 @@ const messages_1 = require("./util/messages");
|
|
|
56
56
|
const debug = (0, debug_1.default)('api');
|
|
57
57
|
let MAX_RETRY_LIMIT;
|
|
58
58
|
let RETRY_DELAY_BASE = 200; // Default base delay in milliseconds
|
|
59
|
-
let TIMEOUT =
|
|
59
|
+
let TIMEOUT = 60000; // Increased from 30000 to 60000 (60 seconds) for large stack syncs
|
|
60
60
|
let Contentstack;
|
|
61
61
|
/**
|
|
62
62
|
* @description Initialize sync utilities API requests
|
|
@@ -169,20 +169,24 @@ const get = (req, RETRY = 1) => {
|
|
|
169
169
|
req.qs = {};
|
|
170
170
|
}
|
|
171
171
|
// Clear the invalid token parameters and reinitialize
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
if (req.qs.pagination_token) {
|
|
176
|
-
delete req.qs.pagination_token;
|
|
177
|
-
}
|
|
172
|
+
delete req.qs.sync_token;
|
|
173
|
+
delete req.qs.pagination_token;
|
|
178
174
|
req.qs.init = true;
|
|
175
|
+
// Reset req.path so it gets rebuilt from Contentstack.apis.sync
|
|
176
|
+
// (req.path has the old query string baked in from line 109)
|
|
177
|
+
delete req.path;
|
|
179
178
|
// Mark this as a recovery attempt to prevent infinite loops
|
|
180
179
|
if (!req._error141Recovery) {
|
|
181
180
|
req._error141Recovery = true;
|
|
182
181
|
debug('Retrying with init=true after Error 141');
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
// Use delayed retry
|
|
183
|
+
timeDelay = Math.pow(Math.SQRT2, RETRY) * RETRY_DELAY_BASE;
|
|
184
|
+
debug(`Error 141 recovery: waiting ${timeDelay}ms before retry`);
|
|
185
|
+
return setTimeout(() => {
|
|
186
|
+
return (0, exports.get)(req, RETRY)
|
|
187
|
+
.then(resolve)
|
|
188
|
+
.catch(reject);
|
|
189
|
+
}, timeDelay);
|
|
186
190
|
}
|
|
187
191
|
else {
|
|
188
192
|
debug('Error 141 recovery already attempted, failing to prevent infinite loop');
|
|
@@ -204,14 +208,28 @@ const get = (req, RETRY = 1) => {
|
|
|
204
208
|
httpRequest.destroy();
|
|
205
209
|
reject(new Error('Request timeout'));
|
|
206
210
|
});
|
|
207
|
-
// Enhanced error handling for
|
|
211
|
+
// Enhanced error handling for network and connection errors
|
|
208
212
|
httpRequest.on('error', (error) => {
|
|
209
|
-
var _a;
|
|
213
|
+
var _a, _b;
|
|
210
214
|
debug(messages_1.MESSAGES.API.REQUEST_ERROR(options.path, error === null || error === void 0 ? void 0 : error.message, error === null || error === void 0 ? void 0 : error.code));
|
|
211
|
-
//
|
|
212
|
-
|
|
215
|
+
// List of retryable network error codes
|
|
216
|
+
const retryableErrors = [
|
|
217
|
+
'ECONNRESET',
|
|
218
|
+
'ETIMEDOUT',
|
|
219
|
+
'ECONNREFUSED',
|
|
220
|
+
'ENOTFOUND',
|
|
221
|
+
'ENETUNREACH',
|
|
222
|
+
'EAI_AGAIN',
|
|
223
|
+
'EPIPE',
|
|
224
|
+
'EHOSTUNREACH', // Host unreachable
|
|
225
|
+
];
|
|
226
|
+
// Check if error is retryable
|
|
227
|
+
const isRetryable = retryableErrors.includes(error === null || error === void 0 ? void 0 : error.code) ||
|
|
228
|
+
((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('socket hang up')) ||
|
|
229
|
+
((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('ETIMEDOUT'));
|
|
230
|
+
if (isRetryable && RETRY <= MAX_RETRY_LIMIT) {
|
|
213
231
|
timeDelay = Math.pow(Math.SQRT2, RETRY) * RETRY_DELAY_BASE;
|
|
214
|
-
debug(
|
|
232
|
+
debug(`Network error ${(error === null || error === void 0 ? void 0 : error.code) || (error === null || error === void 0 ? void 0 : error.message)}: waiting ${timeDelay}ms before retry ${RETRY}/${MAX_RETRY_LIMIT}`);
|
|
215
233
|
RETRY++;
|
|
216
234
|
return setTimeout(() => {
|
|
217
235
|
return (0, exports.get)(req, RETRY)
|
package/dist/core/index.js
CHANGED
|
@@ -42,7 +42,6 @@ exports.unlock = exports.lock = exports.poke = exports.pop = exports.unshift = e
|
|
|
42
42
|
* MIT Licensed
|
|
43
43
|
*/
|
|
44
44
|
const fs = __importStar(require("fs"));
|
|
45
|
-
const path = __importStar(require("path"));
|
|
46
45
|
const debug_1 = __importDefault(require("debug"));
|
|
47
46
|
const events_1 = require("events");
|
|
48
47
|
const lodash_1 = require("lodash");
|
|
@@ -56,7 +55,6 @@ const promise_map_1 = require("../util/promise.map");
|
|
|
56
55
|
const inet_1 = require("./inet");
|
|
57
56
|
const q_1 = require("./q");
|
|
58
57
|
const token_management_1 = require("./token-management");
|
|
59
|
-
const helper_1 = require("../plugins/helper");
|
|
60
58
|
const debug = (0, debug_1.default)('sync-core');
|
|
61
59
|
const emitter = new events_1.EventEmitter();
|
|
62
60
|
const formattedAssetType = '_assets';
|
|
@@ -126,13 +124,8 @@ exports.init = init;
|
|
|
126
124
|
const loadCheckpoint = (checkPointConfig, paths) => {
|
|
127
125
|
if (!(checkPointConfig === null || checkPointConfig === void 0 ? void 0 : checkPointConfig.enabled))
|
|
128
126
|
return;
|
|
129
|
-
//
|
|
127
|
+
// Read checkpoint from configured path only
|
|
130
128
|
let checkpoint = readHiddenFile(paths.checkpoint);
|
|
131
|
-
// Fallback to filePath in config if not found
|
|
132
|
-
if (!checkpoint) {
|
|
133
|
-
const fallbackPath = path.join((0, helper_1.sanitizePath)(__dirname), (0, helper_1.sanitizePath)(checkPointConfig.filePath || ".checkpoint"));
|
|
134
|
-
checkpoint = readHiddenFile(fallbackPath);
|
|
135
|
-
}
|
|
136
129
|
// Set sync token if checkpoint is found
|
|
137
130
|
if (checkpoint) {
|
|
138
131
|
debug(messages_1.MESSAGES.SYNC_CORE.TOKEN_FOUND, checkpoint);
|
|
@@ -361,15 +354,17 @@ const fire = (req) => {
|
|
|
361
354
|
.catch(reject);
|
|
362
355
|
}).catch((error) => {
|
|
363
356
|
debug(messages_1.MESSAGES.SYNC_CORE.ERROR_FIRE, error);
|
|
364
|
-
// Check if this is an Error 141 (
|
|
357
|
+
// Check if this is an Error 141 (outdated token)
|
|
358
|
+
// Note: api.ts already handles recovery by retrying with init=true
|
|
365
359
|
try {
|
|
366
360
|
const parsedError = typeof error === 'string' ? JSON.parse(error) : error;
|
|
367
361
|
if (parsedError.error_code === 141) {
|
|
368
|
-
logger_1.logger.error(
|
|
369
|
-
logger_1.logger.info(
|
|
370
|
-
//
|
|
371
|
-
// Just ensure we don't keep retrying with the bad token
|
|
362
|
+
logger_1.logger.error(messages_1.MESSAGES.SYNC_CORE.OUTDATED_SYNC_TOKEN);
|
|
363
|
+
logger_1.logger.info(messages_1.MESSAGES.SYNC_CORE.SYNC_TOKEN_RENEWAL);
|
|
364
|
+
// Reset flag so next webhook notification can trigger a fresh sync
|
|
372
365
|
flag.SQ = false;
|
|
366
|
+
// Reset sync_token so next sync starts fresh with init=true
|
|
367
|
+
Contentstack.sync_token = undefined;
|
|
373
368
|
}
|
|
374
369
|
}
|
|
375
370
|
catch (parseError) {
|
|
@@ -378,7 +373,6 @@ const fire = (req) => {
|
|
|
378
373
|
if ((0, inet_1.netConnectivityIssues)(error)) {
|
|
379
374
|
flag.SQ = false;
|
|
380
375
|
}
|
|
381
|
-
// do something
|
|
382
376
|
return reject(error);
|
|
383
377
|
});
|
|
384
378
|
});
|
package/dist/plugins/helper.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { cloneDeep } = require('lodash');
|
|
3
|
-
const { getConfig } = require('../index');
|
|
4
3
|
const fieldType = {
|
|
5
4
|
REFERENCE: 'reference',
|
|
6
5
|
GLOBAL_FIELD: 'global_field',
|
|
@@ -186,6 +185,9 @@ const checkReferences = (schema, key) => {
|
|
|
186
185
|
}
|
|
187
186
|
};
|
|
188
187
|
exports.buildAssetObject = (asset, locale, entry_uid, content_type_uid) => {
|
|
188
|
+
// Lazy-load getConfig at runtime to avoid circular dependency
|
|
189
|
+
// (helper.js is loaded during plugin init before index.ts finishes exporting)
|
|
190
|
+
const { getConfig } = require('../index');
|
|
189
191
|
const { contentstack } = getConfig();
|
|
190
192
|
// add locale key to inside of asset
|
|
191
193
|
asset.locale = locale;
|
package/dist/util/messages.js
CHANGED
|
@@ -81,6 +81,8 @@ exports.MESSAGES = {
|
|
|
81
81
|
ERROR_FIRE: 'Error during fire operation.',
|
|
82
82
|
REFIRE_CALLED: (req) => `Re-fire operation triggered with: ${JSON.stringify(req)}`,
|
|
83
83
|
CHECKPOINT_LOCKDOWN: 'Checkpoint: lockdown has been invoked',
|
|
84
|
+
OUTDATED_SYNC_TOKEN: 'Sync token is outdated and no longer accepted by the API. Recovering...',
|
|
85
|
+
SYNC_TOKEN_RENEWAL: 'Renewing sync token. This typically happens after network interruptions or long inactivity.',
|
|
84
86
|
},
|
|
85
87
|
// Main index messages (index.ts)
|
|
86
88
|
INDEX: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/datasync-manager",
|
|
3
3
|
"author": "Contentstack LLC <support@contentstack.com>",
|
|
4
|
-
"version": "2.4.0-beta.
|
|
4
|
+
"version": "2.4.0-beta.1",
|
|
5
5
|
"description": "The primary module of Contentstack DataSync. Syncs Contentstack data with your server using Contentstack Sync API",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"dependencies": {
|