@prodcycle/prodcycle 0.6.2 → 0.6.3
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-client.js +16 -4
- package/package.json +1 -1
package/dist/api-client.js
CHANGED
|
@@ -322,6 +322,7 @@ class ComplianceApiClient {
|
|
|
322
322
|
let lastError = null;
|
|
323
323
|
for (let attempt = 0; attempt < MAX_RETRY_ATTEMPTS; attempt++) {
|
|
324
324
|
let response;
|
|
325
|
+
let responseText;
|
|
325
326
|
try {
|
|
326
327
|
response = await fetch(url, {
|
|
327
328
|
method,
|
|
@@ -332,11 +333,23 @@ class ComplianceApiClient {
|
|
|
332
333
|
...(data !== null ? { body: JSON.stringify(data) } : {}),
|
|
333
334
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
334
335
|
});
|
|
336
|
+
// Body read inside the same try/catch as fetch() because undici can
|
|
337
|
+
// throw mid-stream (ALB drops the connection, abort signal fires
|
|
338
|
+
// during body read, server sends a partial response). Pre-fix this
|
|
339
|
+
// leaked out of `request()` as an unhandled error instead of being
|
|
340
|
+
// retried — long chunked-session scans were especially exposed,
|
|
341
|
+
// since every `appendChunk` call is its own request and any one
|
|
342
|
+
// mid-stream drop torpedoed the whole scan. The chunk write is
|
|
343
|
+
// idempotent on the server (unique `(scan_id, fingerprint)` index),
|
|
344
|
+
// so retry is safe. Mirror of the Python client's catch over
|
|
345
|
+
// `OSError, http.client.HTTPException` — keep both in lockstep.
|
|
346
|
+
responseText = await response.text();
|
|
335
347
|
}
|
|
336
348
|
catch (networkErr) {
|
|
337
|
-
// Connection-level failures (DNS, TCP, TLS)
|
|
338
|
-
//
|
|
339
|
-
// the
|
|
349
|
+
// Connection-level failures (DNS, TCP, TLS) OR body-read-level
|
|
350
|
+
// failures (abort, RST mid-stream). Treat as retryable up to the
|
|
351
|
+
// same cap as 503 — the server may be momentarily down or the
|
|
352
|
+
// network blip may resolve.
|
|
340
353
|
lastError =
|
|
341
354
|
networkErr instanceof Error ? networkErr : new Error(String(networkErr));
|
|
342
355
|
if (attempt < MAX_RETRY_ATTEMPTS - 1) {
|
|
@@ -345,7 +358,6 @@ class ComplianceApiClient {
|
|
|
345
358
|
}
|
|
346
359
|
throw new Error(`Failed to connect to ProdCycle API: ${lastError.message}`);
|
|
347
360
|
}
|
|
348
|
-
const responseText = await response.text();
|
|
349
361
|
let parsed = null;
|
|
350
362
|
try {
|
|
351
363
|
parsed = responseText ? JSON.parse(responseText) : null;
|
package/package.json
CHANGED