Skip to content

Commit 8b045ff

Browse files
Merge pull request #87 from contentstack/development
DX | 10-11-2025 | Release
2 parents 7e7d0c5 + 1a8bda7 commit 8b045ff

File tree

14 files changed

+292
-95
lines changed

14 files changed

+292
-95
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@contentstack/datasync-manager",
33
"author": "Contentstack LLC <[email protected]>",
4-
"version": "2.1.2",
4+
"version": "2.1.3",
55
"description": "The primary module of Contentstack DataSync. Syncs Contentstack data with your server using Contentstack Sync API",
66
"main": "dist/index.js",
77
"dependencies": {

src/api.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { join } from 'path'
1010
import { stringify } from 'querystring'
1111
import { sanitizeUrl } from '@braintree/sanitize-url';
1212
import { readFileSync } from './util/fs'
13+
import { MESSAGES } from './util/messages'
1314

1415
const debug = Debug('api')
1516
let MAX_RETRY_LIMIT
@@ -74,7 +75,7 @@ export const get = (req, RETRY = 1) => {
7475
}
7576

7677
try {
77-
debug(`${options.method.toUpperCase()}: ${options.path}`)
78+
debug(MESSAGES.API.REQUEST(options.method, options.path))
7879
let timeDelay
7980
let body = ''
8081
const httpRequest = request(options, (response) => {
@@ -83,12 +84,12 @@ export const get = (req, RETRY = 1) => {
8384
.setEncoding('utf-8')
8485
.on('data', (chunk) => body += chunk)
8586
.on('end', () => {
86-
debug(`status: ${response.statusCode}.`)
87+
debug(MESSAGES.API.STATUS(response.statusCode))
8788
if (response.statusCode >= 200 && response.statusCode <= 399) {
8889
return resolve(JSON.parse(body))
8990
} else if (response.statusCode === 429) {
9091
timeDelay = Math.pow(Math.SQRT2, RETRY) * RETRY_DELAY_BASE
91-
debug(`API rate limit exceeded. Retrying ${options.path} with ${timeDelay} ms delay`)
92+
debug(MESSAGES.API.RATE_LIMIT(options.path, timeDelay))
9293

9394
return setTimeout(() => {
9495
return get(req, RETRY)
@@ -98,7 +99,7 @@ export const get = (req, RETRY = 1) => {
9899
} else if (response.statusCode >= 500) {
99100
// retry, with delay
100101
timeDelay = Math.pow(Math.SQRT2, RETRY) * RETRY_DELAY_BASE
101-
debug(`Retrying ${options.path} with ${timeDelay} ms delay`)
102+
debug(MESSAGES.API.RETRY(options.path, timeDelay))
102103
RETRY++
103104

104105
return setTimeout(() => {
@@ -107,7 +108,7 @@ export const get = (req, RETRY = 1) => {
107108
.catch(reject)
108109
}, timeDelay)
109110
} else {
110-
debug(`Request failed\n${JSON.stringify(options)}`)
111+
debug(MESSAGES.API.REQUEST_FAILED(options))
111112

112113
return reject(body)
113114
}
@@ -116,19 +117,19 @@ export const get = (req, RETRY = 1) => {
116117

117118
// Set socket timeout to handle socket hang ups
118119
httpRequest.setTimeout(options.timeout, () => {
119-
debug(`Request timeout for ${options.path || 'unknown'}`)
120+
debug(MESSAGES.API.REQUEST_TIMEOUT(options.path))
120121
httpRequest.destroy()
121122
reject(new Error('Request timeout'))
122123
})
123124

124125
// Enhanced error handling for socket hang ups and connection resets
125126
httpRequest.on('error', (error: any) => {
126-
debug(`Request error for ${options.path || 'unknown'}: ${error?.message || 'Unknown error'} (${error?.code || 'NO_CODE'})`)
127+
debug(MESSAGES.API.REQUEST_ERROR(options.path, error?.message, error?.code))
127128

128129
// Handle socket hang up and connection reset errors with retry
129130
if ((error?.code === 'ECONNRESET' || error?.message?.includes('socket hang up')) && RETRY <= MAX_RETRY_LIMIT) {
130131
timeDelay = Math.pow(Math.SQRT2, RETRY) * RETRY_DELAY_BASE
131-
debug(`Socket hang up detected. Retrying ${options.path || 'unknown'} with ${timeDelay} ms delay (attempt ${RETRY}/${MAX_RETRY_LIMIT})`)
132+
debug(MESSAGES.API.SOCKET_HANGUP_RETRY(options.path, timeDelay, RETRY, MAX_RETRY_LIMIT))
132133
RETRY++
133134

134135
return setTimeout(() => {

src/core/index.ts

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { get, init as initAPI } from '../api'
1313
import { existsSync, readFileSync } from '../util/fs'
1414
import { filterItems, formatItems, groupItems, markCheckpoint } from '../util/index'
1515
import { logger } from '../util/logger'
16+
import { MESSAGES } from '../util/messages'
1617
import { map } from '../util/promise.map'
1718
import { netConnectivityIssues } from './inet'
1819
import { Q as Queue } from './q'
@@ -76,15 +77,15 @@ export const init = (contentStore, assetStore) => {
7677
config = getConfig()
7778
Q = new Queue(contentStore, assetStore, config)
7879
initAPI(config.contentstack)
79-
debug('Sync core:start invoked')
80+
debug(MESSAGES.SYNC_CORE.START)
8081

8182
return new Promise((resolve, reject) => {
8283
try {
8384
Contentstack = config.contentstack
8485
const checkPointConfig: ICheckpoint = config.checkpoint
8586
const paths = config.paths
8687
const environment = Contentstack.environment || process.env.NODE_ENV || 'development'
87-
debug(`Environment: ${environment}`)
88+
debug(MESSAGES.SYNC_CORE.ENVIRONMENT(environment))
8889
const request: any = {
8990
qs: {
9091
environment,
@@ -136,23 +137,23 @@ const loadCheckpoint = (checkPointConfig: ICheckpoint, paths: any): void => {
136137

137138
// Set sync token if checkpoint is found
138139
if (checkpoint) {
139-
debug("Found sync token in checkpoint file:", checkpoint);
140+
debug(MESSAGES.SYNC_CORE.TOKEN_FOUND, checkpoint);
140141
Contentstack.sync_token = checkpoint.token;
141-
debug("Using sync token:", Contentstack.sync_token);
142+
debug(MESSAGES.SYNC_CORE.TOKEN_USING, Contentstack.sync_token);
142143
}
143144
};
144145

145146

146147
function readHiddenFile(filePath: string) {
147148
try {
148149
if (!fs.existsSync(filePath)) {
149-
logger.error("File does not exist:", filePath);
150+
logger.error(MESSAGES.SYNC_CORE.FILE_NOT_FOUND(filePath));
150151
return;
151152
}
152153
const data = fs.readFileSync(filePath, "utf8");
153154
return JSON.parse(data);
154155
} catch (err) {
155-
logger.error("Error reading file:", err);
156+
logger.error(MESSAGES.SYNC_CORE.FILE_READ_ERROR(err));
156157
return undefined;
157158
}
158159
}
@@ -174,15 +175,15 @@ export const pop = () => {
174175
*/
175176
export const poke = async () => {
176177
try {
177-
debug('Invoked poke');
178-
logger.info('Received \'contentstack sync\' notification')
178+
debug(MESSAGES.SYNC_CORE.POKE_INVOKED);
179+
logger.info(MESSAGES.SYNC_CORE.POKE_NOTIFICATION)
179180
if (!flag.lockdown) {
180181
flag.WQ = true
181182
return await check()
182183
}
183184
return null;
184185
} catch (error) {
185-
debug('Error [poke]', error);
186+
debug(MESSAGES.SYNC_CORE.POKE_ERROR, error);
186187
throw error;
187188
}
188189
}
@@ -193,24 +194,24 @@ export const poke = async () => {
193194
*/
194195
const check = async () => {
195196
try {
196-
debug(`Check called. SQ status is ${flag.SQ} and WQ status is ${flag.WQ}`)
197+
debug(MESSAGES.SYNC_CORE.CHECK_CALLED(flag.SQ, flag.WQ))
197198
if (!flag.SQ && flag.WQ) {
198199
flag.WQ = false
199200
flag.SQ = true
200201
await sync();
201-
debug(`Sync completed and SQ flag updated. Cooloff duration is ${config.syncManager.cooloff}`)
202+
debug(MESSAGES.SYNC_CORE.CHECK_COMPLETE(config.syncManager.cooloff))
202203
setTimeout(() => {
203204
flag.SQ = false
204205
emitter.emit('check')
205206
}, config.syncManager.cooloff)
206207
}
207208
} catch (error) {
208209
logger.error(error)
209-
debug('Error [check]', error);
210+
debug(MESSAGES.SYNC_CORE.CHECK_ERROR, error);
210211
check().then(() => {
211-
debug('passed [check] error');
212+
debug(MESSAGES.SYNC_CORE.CHECK_RECOVERED);
212213
}).catch((error) => {
213-
debug('failed [check] error', error);
214+
debug(MESSAGES.SYNC_CORE.CHECK_FAILED, error);
214215
});
215216
throw error;
216217
}
@@ -221,9 +222,9 @@ const check = async () => {
221222
*/
222223
const sync = async () => {
223224
try {
224-
debug('started [sync]');
225+
debug(MESSAGES.SYNC_CORE.SYNC_STARTED);
225226
const tokenObject = await getToken();
226-
debug('tokenObject [sync]', tokenObject);
227+
debug(MESSAGES.SYNC_CORE.SYNC_TOKEN_OBJECT, tokenObject);
227228
const token: IToken = (tokenObject as IToken)
228229
const request: any = {
229230
qs: {
@@ -234,7 +235,7 @@ const sync = async () => {
234235
}
235236
return await fire(request)
236237
} catch (error) {
237-
debug('Error [sync]', error);
238+
debug(MESSAGES.SYNC_CORE.SYNC_ERROR, error);
238239
throw error
239240
}
240241
}
@@ -243,15 +244,15 @@ const sync = async () => {
243244
* @description Used to lockdown the 'sync' process in case of exceptions
244245
*/
245246
export const lock = () => {
246-
debug('Contentstack sync locked..')
247+
debug(MESSAGES.SYNC_CORE.SYNC_LOCKED)
247248
flag.lockdown = true
248249
}
249250

250251
/**
251252
* @description Used to unlock the 'sync' process in case of errors/exceptions
252253
*/
253254
export const unlock = (refire?: boolean) => {
254-
debug('Contentstack sync unlocked..', refire)
255+
debug(MESSAGES.SYNC_CORE.SYNC_UNLOCKED, refire)
255256
flag.lockdown = false
256257
if (typeof refire === 'boolean' && refire) {
257258
flag.WQ = true
@@ -269,7 +270,7 @@ export const unlock = (refire?: boolean) => {
269270
* @param {Object} req - Contentstack sync API request object
270271
*/
271272
const fire = (req: IApiRequest) => {
272-
debug(`Fire called with: ${JSON.stringify(req)}`)
273+
debug(MESSAGES.SYNC_CORE.FIRE_CALLED(req))
273274
flag.SQ = true
274275

275276
return new Promise((resolve, reject) => {
@@ -279,7 +280,7 @@ const fire = (req: IApiRequest) => {
279280
delete req.qs.sync_token
280281
delete req.path
281282
const syncResponse: ISyncResponse = response
282-
debug('Response [fire]', syncResponse.items.length);
283+
debug(MESSAGES.SYNC_CORE.FIRE_COMPLETE(syncResponse.items.length));
283284
if (syncResponse.items.length) {
284285
return filterItems(syncResponse, config).then(() => {
285286
if (syncResponse.items.length === 0) {
@@ -319,7 +320,7 @@ const fire = (req: IApiRequest) => {
319320
return map(contentTypeUids, (uid) => {
320321

321322
return new Promise((mapResolve, mapReject) => {
322-
debug(`API called with for content type: ${uid}`)
323+
debug(MESSAGES.SYNC_CORE.API_CALL_CT(uid))
323324
return get({
324325
path: `${Contentstack.apis.content_types}${uid}`,
325326
qs: {
@@ -344,7 +345,7 @@ const fire = (req: IApiRequest) => {
344345

345346
return mapReject(err)
346347
}).catch((error) => {
347-
debug('Error [map] fetching content type schema:', error)
348+
debug(MESSAGES.SYNC_CORE.ERROR_MAP, error)
348349
if (netConnectivityIssues(error)) {
349350
flag.SQ = false
350351
}
@@ -361,11 +362,11 @@ const fire = (req: IApiRequest) => {
361362
flag.SQ = false
362363
}
363364
// Errorred while fetching content type schema
364-
debug('Error [mapResolve]:', error)
365+
debug(MESSAGES.SYNC_CORE.ERROR_MAP_RESOLVE, error)
365366
return reject(error)
366367
})
367368
}).catch((processError) => {
368-
debug('Error [filterItems]:', processError)
369+
debug(MESSAGES.SYNC_CORE.ERROR_FILTER_ITEMS, processError)
369370
return reject(processError)
370371
})
371372
}
@@ -374,7 +375,7 @@ const fire = (req: IApiRequest) => {
374375
.then(resolve)
375376
.catch(reject)
376377
}).catch((error) => {
377-
debug('Error [fire]', error);
378+
debug(MESSAGES.SYNC_CORE.ERROR_FIRE, error);
378379
if (netConnectivityIssues(error)) {
379380
flag.SQ = false
380381
}
@@ -406,7 +407,7 @@ const postProcess = (req, resp) => {
406407
req.qs[name] = resp[name]
407408

408409
if (flag.lockdown) {
409-
logger.log('Checkpoint: lockdown has been invoked')
410+
logger.log(MESSAGES.SYNC_CORE.CHECKPOINT_LOCKDOWN)
410411
flag.requestCache = {
411412
params: req,
412413
reject,
@@ -419,7 +420,7 @@ const postProcess = (req, resp) => {
419420
return resolve('')
420421
}
421422

422-
debug(`Re-Fire called with: ${JSON.stringify(req)}`)
423+
debug(MESSAGES.SYNC_CORE.REFIRE_CALLED(req))
423424
return fire(req)
424425
.then(resolve)
425426
.catch(reject);

src/core/inet.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import dnsSocket from 'dns-socket'
99
import { EventEmitter } from 'events'
1010
import { getConfig } from '../index'
1111
import { logger } from '../util/logger'
12+
import { MESSAGES } from '../util/messages'
1213
import { poke } from './index'
1314

1415
interface ISyncManager {
@@ -47,7 +48,7 @@ export const init = () => {
4748
port = sm.inet.port
4849
dns = sm.inet.dns
4950
currentTimeout = sm.inet.retryTimeout
50-
debug(`inet initiated - waiting ${currentTimeout} before checking connectivity.`)
51+
debug(MESSAGES.INET.INITIATED(currentTimeout))
5152
// start checking for net connectivity, 30 seconds after the app has started
5253
setTimeout(checkNetConnectivity, currentTimeout)
5354
}
@@ -57,14 +58,14 @@ export const checkNetConnectivity = () => {
5758
retries: sm.inet.retries,
5859
timeout: sm.inet.timeout,
5960
})
60-
debug('checking network connectivity')
61+
debug(MESSAGES.INET.CHECKING)
6162
socket.query(query, port, dns, (err) => {
6263
if (err) {
63-
debug(`errorred.. ${err}`)
64+
debug(MESSAGES.INET.CHECK_FAILED(err))
6465
disconnected = true
6566

6667
return socket.destroy(() => {
67-
debug('socket destroyed')
68+
debug(MESSAGES.INET.CLEANUP_ERROR)
6869
emitter.emit('disconnected', currentTimeout += sm.inet.retryIncrement)
6970
})
7071
} else if (disconnected) {
@@ -73,7 +74,7 @@ export const checkNetConnectivity = () => {
7374
disconnected = false
7475

7576
return socket.destroy(() => {
76-
debug('socket destroyed')
77+
debug(MESSAGES.INET.CLEANUP_SUCCESS)
7778
emitter.emit('ok')
7879
})
7980
})
@@ -92,12 +93,12 @@ export const netConnectivityIssues = (error) => {
9293

9394
emitter.on('ok', () => {
9495
currentTimeout = sm.inet.retryTimeout
95-
debug(`pinging ${sm.inet.host} in ${sm.inet.timeout} ms`)
96+
debug(MESSAGES.INET.PINGING(sm.inet.host, sm.inet.timeout))
9697
setTimeout(checkNetConnectivity, sm.inet.timeout)
9798
})
9899

99100
emitter.on('disconnected', (timeout) => {
100-
logger.warn('Network disconnected')
101-
debug(`pinging ${sm.inet.host} in ${timeout} ms`)
101+
logger.warn(MESSAGES.INET.DISCONNECTED)
102+
debug(MESSAGES.INET.PINGING(sm.inet.host, timeout))
102103
setTimeout(checkNetConnectivity, timeout)
103104
})

0 commit comments

Comments
 (0)