Skip to content

Commit 605bb61

Browse files
authored
Merge pull request #80 from DeepLcom/acl-2909-retry-on-econnreset
Acl 2909 retry on econnreset
2 parents d54b131 + 02d7410 commit 605bb61

12 files changed

Lines changed: 83 additions & 68 deletions

.bumpversion.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Configuration file for bumpversion
22
# See https://github.com/callowayproject/bump-my-version
33
[tool.bumpversion]
4-
current_version = "1.26.0"
4+
current_version = "1.27.0"
55
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
66
serialize = ["{major}.{minor}.{patch}"]
77
search = "{current_version}"

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
9+
## [1.27.0] - 2026-04-27
10+
### Changed
11+
- Replaced the `uuid` dependency with Node's built-in `crypto.randomUUID()`.
12+
Resolves GHSA-w5hq-g745-h8pq (`uuid <14.0.0`) and removes a runtime
13+
dependency.
14+
- Bumped minimum Node version from `>=12.0` to `>=14.17`. Node 12 reached
15+
end of life in April 2022, and `crypto.randomUUID()` is available from
16+
Node 14.17 onward.
17+
18+
### Fixed
19+
- HTTP requests that fail with `ECONNRESET`, `EPIPE`, or `EAI_AGAIN` are now
20+
retried. Previously these were classified as non-retryable, surfacing
21+
transient transport failures (e.g. stale keep-alive sockets) as hard errors
22+
on the first attempt. Behavior now aligns with deepl-python.
23+
824
### Security
925
- Bump follow-redirects to 1.16.0 due to GHSA-r4q5-vmmm-2653.
1026

package-lock.json

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

package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "deepl-node",
33
"description": "deepl-node is the official DeepL Node.js client library",
4-
"version": "1.26.0",
4+
"version": "1.27.0",
55
"author": "DeepL SE <open-source@deepl.com> (https://www.deepl.com)",
66
"license": "MIT",
77
"repository": {
@@ -11,7 +11,7 @@
1111
"bugs": "https://github.com/DeepLcom/deepl-node/issues",
1212
"homepage": "https://www.deepl.com/",
1313
"engines": {
14-
"node": ">=12.0"
14+
"node": ">=14.17"
1515
},
1616
"keywords": [
1717
"deepl",
@@ -23,14 +23,12 @@
2323
"adm-zip": "^0.5.16",
2424
"axios": "^1.7.4",
2525
"form-data": "^3.0.4",
26-
"loglevel": ">=1.6.2",
27-
"uuid": "^8.3.2"
26+
"loglevel": ">=1.6.2"
2827
},
2928
"devDependencies": {
3029
"@types/adm-zip": "^0.5.7",
3130
"@types/jest": "^29.5.0",
3231
"@types/mock-fs": "^4.13.4",
33-
"@types/uuid": "^8.3.4",
3432
"@typescript-eslint/eslint-plugin": "^5.6.0",
3533
"@typescript-eslint/parser": "^5.6.0",
3634
"dotenv": "^16.4.7",

src/client.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ import * as http from 'http';
1515

1616
type HttpMethod = 'GET' | 'DELETE' | 'POST' | 'PUT' | 'PATCH';
1717

18+
/**
19+
* Axios error codes for transient transport-level failures that should be retried.
20+
* Mirrors deepl-python's broader ConnectionError retry coverage.
21+
* @internal
22+
*/
23+
export const RETRYABLE_AXIOS_ERROR_CODES = new Set([
24+
'ETIMEDOUT',
25+
'ECONNABORTED',
26+
'ECONNRESET',
27+
'EPIPE',
28+
'EAI_AGAIN',
29+
]);
30+
1831
const axiosInstance = axios.create({
1932
httpAgent: new http.Agent({ keepAlive: true }),
2033
httpsAgent: new https.Agent({ keepAlive: true }),
@@ -261,9 +274,7 @@ export class HttpClient {
261274

262275
const error = new ConnectionError(`Connection failure: ${message}`);
263276
error.error = axiosError;
264-
if (axiosError.code === 'ETIMEDOUT') {
265-
error.shouldRetry = true;
266-
} else if (axiosError.code === 'ECONNABORTED') {
277+
if (axiosError.code !== undefined && RETRYABLE_AXIOS_ERROR_CODES.has(axiosError.code)) {
267278
error.shouldRetry = true;
268279
} else {
269280
logDebug('Unrecognized axios error', axiosError);

src/documentMinifier.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as path from 'path';
22
import * as fs from 'fs';
33
import * as os from 'os';
4-
import { v4 as uuidv4 } from 'uuid';
4+
import { randomUUID } from 'crypto';
55
import { DocumentDeminificationError, DocumentMinificationError } from './errors';
66
import AdmZip from 'adm-zip';
77
import { FsHelper } from './fsHelper';
@@ -283,7 +283,7 @@ export class DocumentMinifier implements IDocumentMinifier {
283283
* @throws {DocumentMinificationError} If the temporary directory could not be created
284284
*/
285285
private static createTemporaryDirectory(): string {
286-
const tempDir = path.join(os.tmpdir(), 'document_minification_' + uuidv4());
286+
const tempDir = path.join(os.tmpdir(), 'document_minification_' + randomUUID());
287287

288288
if (fs.existsSync(tempDir)) {
289289
throw new DocumentMinificationError(

src/translator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ export class Translator {
697697
sendPlatformInfo: boolean,
698698
appInfo: AppInfo | undefined,
699699
): string {
700-
let libraryInfoString = 'deepl-node/1.26.0';
700+
let libraryInfoString = 'deepl-node/1.27.0';
701701
if (sendPlatformInfo) {
702702
const systemType = os.type();
703703
const systemVersion = os.version();

0 commit comments

Comments
 (0)