locize-cli 12.3.0 → 12.3.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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  Project versioning adheres to [Semantic Versioning](http://semver.org/).
6
6
  Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
7
7
 
8
+ ## [12.3.1](https://github.com/locize/locize-cli/compare/v12.3.0...v12.3.1) - 2026-06-18
9
+
10
+ - request: retry transient network failures with exponential backoff and jitter
11
+ instead of a fixed 5s delay. This spreads retries so that bursts of
12
+ concurrent CLI runs (e.g. in CI) no longer retry in lockstep and hit the API
13
+ at the same instant.
14
+
8
15
  ## [12.3.0](https://github.com/locize/locize-cli/compare/v12.2.0...v12.3.0) - 2026-06-10
9
16
 
10
17
  - sync: creates missing remote languages on the fly. A project without any
package/dist/cjs/cli.js CHANGED
@@ -50,7 +50,7 @@ const program = new commander.Command();
50
50
 
51
51
  program
52
52
  .description('The official locize CLI.')
53
- .version('12.3.0'); // This string is replaced with the actual version at build time by rollup
53
+ .version('12.3.1'); // This string is replaced with the actual version at build time by rollup
54
54
  // .option('-a, --api-endpoint <url>', `Specify the api-endpoint url that should be used (default: ${defaultApiEndpoint})`)
55
55
  // .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`);
56
56
 
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "locize-cli",
3
- "version": "12.3.0",
3
+ "version": "12.3.1",
4
4
  "type": "commonjs"
5
5
  }
@@ -7,6 +7,10 @@ var CacheableLookup = require('cacheable-lookup');
7
7
  const cacheable = new CacheableLookup();
8
8
  cacheable.install(https.globalAgent);
9
9
 
10
+ const RETRY_MAX_ATTEMPTS = 3;
11
+ const RETRY_BASE_DELAY_MS = 2000;
12
+ const RETRY_MAX_DELAY_MS = 30000;
13
+
10
14
  const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || process.env.https_proxy || process.env.HTTPS_PROXY;
11
15
  const isRetriableError = (err) => {
12
16
  return err && err.message && (
@@ -39,7 +43,7 @@ async function request (url, options) {
39
43
  }
40
44
 
41
45
  options.headers = options.headers || {};
42
- options.headers['User-Agent'] = `locize-cli/v12.3.0 (node/${process.version}; ${process.platform} ${process.arch})`; // This string is replaced with the actual version at build time by rollup
46
+ options.headers['User-Agent'] = `locize-cli/v12.3.1 (node/${process.version}; ${process.platform} ${process.arch})`; // This string is replaced with the actual version at build time by rollup
43
47
  options.headers['X-User-Agent'] = options.headers['User-Agent'];
44
48
  if (options.body || options.method !== 'get') options.headers['Content-Type'] = 'application/json';
45
49
  if (options.body) {
@@ -49,19 +53,24 @@ async function request (url, options) {
49
53
  }
50
54
  if (options.headers['Authorization'] === undefined) delete options.headers['Authorization'];
51
55
 
52
- async function retriableFetch (maxRetries) {
56
+ async function retriableFetch (retriesLeft, attempt = 0) {
53
57
  try {
54
58
  const response = await fetch(url, options);
55
59
  const result = await handleResponse(response);
56
60
  return result
57
61
  } catch (err) {
58
- if (maxRetries < 1) throw err
62
+ if (retriesLeft < 1) throw err
59
63
  if (!isRetriableError(err)) throw err
60
- await new Promise(resolve => setTimeout(resolve, 5000));
61
- return retriableFetch(--maxRetries)
64
+ // Exponential backoff with equal jitter: spreads retries so a burst of
65
+ // concurrent CLI runs (e.g. CI) doesn't all retry in lockstep and
66
+ // hammer the API at the same instant.
67
+ const expDelay = Math.min(RETRY_MAX_DELAY_MS, RETRY_BASE_DELAY_MS * (2 ** attempt));
68
+ const delay = Math.round(expDelay / 2 + Math.random() * (expDelay / 2));
69
+ await new Promise(resolve => setTimeout(resolve, delay));
70
+ return retriableFetch(retriesLeft - 1, attempt + 1)
62
71
  }
63
72
  }
64
- return retriableFetch(3)
73
+ return retriableFetch(RETRY_MAX_ATTEMPTS)
65
74
  }
66
75
 
67
76
  module.exports = request;
package/dist/esm/cli.js CHANGED
@@ -48,7 +48,7 @@ const program = new Command();
48
48
 
49
49
  program
50
50
  .description('The official locize CLI.')
51
- .version('12.3.0'); // This string is replaced with the actual version at build time by rollup
51
+ .version('12.3.1'); // This string is replaced with the actual version at build time by rollup
52
52
  // .option('-a, --api-endpoint <url>', `Specify the api-endpoint url that should be used (default: ${defaultApiEndpoint})`)
53
53
  // .option('-C, --config-path <configPath>', `Specify the path to the optional locize config file (default: ${configInWorkingDirectory} or ${configInHome})`);
54
54
 
@@ -5,6 +5,10 @@ import CacheableLookup from 'cacheable-lookup';
5
5
  const cacheable = new CacheableLookup();
6
6
  cacheable.install(https.globalAgent);
7
7
 
8
+ const RETRY_MAX_ATTEMPTS = 3;
9
+ const RETRY_BASE_DELAY_MS = 2000;
10
+ const RETRY_MAX_DELAY_MS = 30000;
11
+
8
12
  const httpProxy = process.env.http_proxy || process.env.HTTP_PROXY || process.env.https_proxy || process.env.HTTPS_PROXY;
9
13
  const isRetriableError = (err) => {
10
14
  return err && err.message && (
@@ -37,7 +41,7 @@ async function request (url, options) {
37
41
  }
38
42
 
39
43
  options.headers = options.headers || {};
40
- options.headers['User-Agent'] = `locize-cli/v12.3.0 (node/${process.version}; ${process.platform} ${process.arch})`; // This string is replaced with the actual version at build time by rollup
44
+ options.headers['User-Agent'] = `locize-cli/v12.3.1 (node/${process.version}; ${process.platform} ${process.arch})`; // This string is replaced with the actual version at build time by rollup
41
45
  options.headers['X-User-Agent'] = options.headers['User-Agent'];
42
46
  if (options.body || options.method !== 'get') options.headers['Content-Type'] = 'application/json';
43
47
  if (options.body) {
@@ -47,19 +51,24 @@ async function request (url, options) {
47
51
  }
48
52
  if (options.headers['Authorization'] === undefined) delete options.headers['Authorization'];
49
53
 
50
- async function retriableFetch (maxRetries) {
54
+ async function retriableFetch (retriesLeft, attempt = 0) {
51
55
  try {
52
56
  const response = await fetch(url, options);
53
57
  const result = await handleResponse(response);
54
58
  return result
55
59
  } catch (err) {
56
- if (maxRetries < 1) throw err
60
+ if (retriesLeft < 1) throw err
57
61
  if (!isRetriableError(err)) throw err
58
- await new Promise(resolve => setTimeout(resolve, 5000));
59
- return retriableFetch(--maxRetries)
62
+ // Exponential backoff with equal jitter: spreads retries so a burst of
63
+ // concurrent CLI runs (e.g. CI) doesn't all retry in lockstep and
64
+ // hammer the API at the same instant.
65
+ const expDelay = Math.min(RETRY_MAX_DELAY_MS, RETRY_BASE_DELAY_MS * (2 ** attempt));
66
+ const delay = Math.round(expDelay / 2 + Math.random() * (expDelay / 2));
67
+ await new Promise(resolve => setTimeout(resolve, delay));
68
+ return retriableFetch(retriesLeft - 1, attempt + 1)
60
69
  }
61
70
  }
62
- return retriableFetch(3)
71
+ return retriableFetch(RETRY_MAX_ATTEMPTS)
63
72
  }
64
73
 
65
74
  export { request as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locize-cli",
3
- "version": "12.3.0",
3
+ "version": "12.3.1",
4
4
  "description": "locize cli to import locales",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",