@socketsecurity/sdk 1.10.1 → 1.11.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 +19 -0
- package/README.md +153 -311
- package/dist/constants.js +23 -117
- package/dist/file-upload.js +118 -127
- package/dist/http-client.d.ts +11 -8
- package/dist/http-client.js +281 -223
- package/dist/index.js +43 -48
- package/dist/package.json.js +212 -0
- package/dist/quota-utils.d.ts +13 -6
- package/dist/quota-utils.js +128 -105
- package/dist/socket-sdk-class.d.ts +1 -1
- package/dist/socket-sdk-class.js +1488 -1407
- package/dist/testing.d.ts +453 -0
- package/dist/testing.js +387 -0
- package/dist/types.d.ts +26 -0
- package/dist/user-agent.js +11 -7
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +66 -60
- package/package.json +27 -6
- package/dist/promise-queue.js +0 -91
- package/dist/types.js +0 -3
package/dist/constants.js
CHANGED
|
@@ -1,124 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.publicPolicy = exports.httpAgentNames = exports.DEFAULT_USER_AGENT = void 0;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _package = require('./package.json.js');
|
|
4
|
+
var userAgent = require('./user-agent.js');
|
|
5
|
+
|
|
7
6
|
/**
|
|
8
7
|
* @fileoverview Configuration constants and enums for the Socket SDK.
|
|
9
8
|
* Provides default values, HTTP agents, and public policy configurations for API interactions.
|
|
10
9
|
*/
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
10
|
+
|
|
11
|
+
const DEFAULT_USER_AGENT = userAgent.createUserAgentFromPkgJson(_package.default);
|
|
12
|
+
|
|
14
13
|
// https://github.com/sindresorhus/got/blob/v14.4.6/documentation/2-options.md#agent
|
|
15
14
|
// Valid HTTP agent names for Got-style agent configuration compatibility.
|
|
16
|
-
|
|
15
|
+
const httpAgentNames = new Set(['http', 'https', 'http2']);
|
|
16
|
+
|
|
17
17
|
// Public security policy.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
['mediumCVE', 'monitor'],
|
|
32
|
-
['mildCVE', 'monitor'],
|
|
33
|
-
['shrinkwrap', 'monitor'],
|
|
34
|
-
['telemetry', 'monitor'],
|
|
35
|
-
['unpopularPackage', 'monitor'],
|
|
36
|
-
['unstableOwnership', 'monitor'],
|
|
37
|
-
// ignore (85):
|
|
38
|
-
['ambiguousClassifier', 'ignore'],
|
|
39
|
-
['badEncoding', 'ignore'],
|
|
40
|
-
['badSemver', 'ignore'],
|
|
41
|
-
['badSemverDependency', 'ignore'],
|
|
42
|
-
['bidi', 'ignore'],
|
|
43
|
-
['binScriptConfusion', 'ignore'],
|
|
44
|
-
['chromeContentScript', 'ignore'],
|
|
45
|
-
['chromeHostPermission', 'ignore'],
|
|
46
|
-
['chromePermission', 'ignore'],
|
|
47
|
-
['chromeWildcardHostPermission', 'ignore'],
|
|
48
|
-
['chronoAnomaly', 'ignore'],
|
|
49
|
-
['compromisedSSHKey', 'ignore'],
|
|
50
|
-
['copyleftLicense', 'ignore'],
|
|
51
|
-
['cve', 'ignore'],
|
|
52
|
-
['debugAccess', 'ignore'],
|
|
53
|
-
['deprecatedLicense', 'ignore'],
|
|
54
|
-
['deprecatedException', 'ignore'],
|
|
55
|
-
['dynamicRequire', 'ignore'],
|
|
56
|
-
['emptyPackage', 'ignore'],
|
|
57
|
-
['envVars', 'ignore'],
|
|
58
|
-
['explicitlyUnlicensedItem', 'ignore'],
|
|
59
|
-
['extraneousDependency', 'ignore'],
|
|
60
|
-
['fileDependency', 'ignore'],
|
|
61
|
-
['filesystemAccess', 'ignore'],
|
|
62
|
-
['floatingDependency', 'ignore'],
|
|
63
|
-
['gitHubDependency', 'ignore'],
|
|
64
|
-
['gptAnomaly', 'ignore'],
|
|
65
|
-
['gptDidYouMean', 'ignore'],
|
|
66
|
-
['gptMalware', 'ignore'],
|
|
67
|
-
['gptSecurity', 'ignore'],
|
|
68
|
-
['hasNativeCode', 'ignore'],
|
|
69
|
-
['highEntropyStrings', 'ignore'],
|
|
70
|
-
['homoglyphs', 'ignore'],
|
|
71
|
-
['installScripts', 'ignore'],
|
|
72
|
-
['invalidPackageJSON', 'ignore'],
|
|
73
|
-
['invisibleChars', 'ignore'],
|
|
74
|
-
['licenseChange', 'ignore'],
|
|
75
|
-
['licenseException', 'ignore'],
|
|
76
|
-
['longStrings', 'ignore'],
|
|
77
|
-
['majorRefactor', 'ignore'],
|
|
78
|
-
['manifestConfusion', 'ignore'],
|
|
79
|
-
['minifiedFile', 'ignore'],
|
|
80
|
-
['miscLicenseIssues', 'ignore'],
|
|
81
|
-
['missingAuthor', 'ignore'],
|
|
82
|
-
['missingDependency', 'ignore'],
|
|
83
|
-
['missingLicense', 'ignore'],
|
|
84
|
-
['missingTarball', 'ignore'],
|
|
85
|
-
['mixedLicense', 'ignore'],
|
|
86
|
-
['modifiedException', 'ignore'],
|
|
87
|
-
['modifiedLicense', 'ignore'],
|
|
88
|
-
['networkAccess', 'ignore'],
|
|
89
|
-
['newAuthor', 'ignore'],
|
|
90
|
-
['noAuthorData', 'ignore'],
|
|
91
|
-
['noBugTracker', 'ignore'],
|
|
92
|
-
['noLicenseFound', 'ignore'],
|
|
93
|
-
['noREADME', 'ignore'],
|
|
94
|
-
['noRepository', 'ignore'],
|
|
95
|
-
['noTests', 'ignore'],
|
|
96
|
-
['noV1', 'ignore'],
|
|
97
|
-
['noWebsite', 'ignore'],
|
|
98
|
-
['nonOSILicense', 'ignore'],
|
|
99
|
-
['nonSPDXLicense', 'ignore'],
|
|
100
|
-
['nonpermissiveLicense', 'ignore'],
|
|
101
|
-
['notice', 'ignore'],
|
|
102
|
-
['obfuscatedRequire', 'ignore'],
|
|
103
|
-
['peerDependency', 'ignore'],
|
|
104
|
-
['potentialVulnerability', 'ignore'],
|
|
105
|
-
['semverAnomaly', 'ignore'],
|
|
106
|
-
['shellAccess', 'ignore'],
|
|
107
|
-
['shellScriptOverride', 'ignore'],
|
|
108
|
-
['socketUpgradeAvailable', 'ignore'],
|
|
109
|
-
['suspiciousStarActivity', 'ignore'],
|
|
110
|
-
['suspiciousString', 'ignore'],
|
|
111
|
-
['trivialPackage', 'ignore'],
|
|
112
|
-
['typeModuleCompatibility', 'ignore'],
|
|
113
|
-
['uncaughtOptionalDependency', 'ignore'],
|
|
114
|
-
['unclearLicense', 'ignore'],
|
|
115
|
-
['unidentifiedLicense', 'ignore'],
|
|
116
|
-
['unmaintained', 'ignore'],
|
|
117
|
-
['unpublished', 'ignore'],
|
|
118
|
-
['unresolvedRequire', 'ignore'],
|
|
119
|
-
['unsafeCopyright', 'ignore'],
|
|
120
|
-
['unusedDependency', 'ignore'],
|
|
121
|
-
['urlStrings', 'ignore'],
|
|
122
|
-
['usesEval', 'ignore'],
|
|
123
|
-
['zeroWidth', 'ignore'],
|
|
124
|
-
]);
|
|
18
|
+
const publicPolicy = new Map([
|
|
19
|
+
// error (1):
|
|
20
|
+
['malware', 'error'],
|
|
21
|
+
// warn (7):
|
|
22
|
+
['criticalCVE', 'warn'], ['didYouMean', 'warn'], ['gitDependency', 'warn'], ['httpDependency', 'warn'], ['licenseSpdxDisj', 'warn'], ['obfuscatedFile', 'warn'], ['troll', 'warn'],
|
|
23
|
+
// monitor (7):
|
|
24
|
+
['deprecated', 'monitor'], ['mediumCVE', 'monitor'], ['mildCVE', 'monitor'], ['shrinkwrap', 'monitor'], ['telemetry', 'monitor'], ['unpopularPackage', 'monitor'], ['unstableOwnership', 'monitor'],
|
|
25
|
+
// ignore (85):
|
|
26
|
+
['ambiguousClassifier', 'ignore'], ['badEncoding', 'ignore'], ['badSemver', 'ignore'], ['badSemverDependency', 'ignore'], ['bidi', 'ignore'], ['binScriptConfusion', 'ignore'], ['chromeContentScript', 'ignore'], ['chromeHostPermission', 'ignore'], ['chromePermission', 'ignore'], ['chromeWildcardHostPermission', 'ignore'], ['chronoAnomaly', 'ignore'], ['compromisedSSHKey', 'ignore'], ['copyleftLicense', 'ignore'], ['cve', 'ignore'], ['debugAccess', 'ignore'], ['deprecatedLicense', 'ignore'], ['deprecatedException', 'ignore'], ['dynamicRequire', 'ignore'], ['emptyPackage', 'ignore'], ['envVars', 'ignore'], ['explicitlyUnlicensedItem', 'ignore'], ['extraneousDependency', 'ignore'], ['fileDependency', 'ignore'], ['filesystemAccess', 'ignore'], ['floatingDependency', 'ignore'], ['gitHubDependency', 'ignore'], ['gptAnomaly', 'ignore'], ['gptDidYouMean', 'ignore'], ['gptMalware', 'ignore'], ['gptSecurity', 'ignore'], ['hasNativeCode', 'ignore'], ['highEntropyStrings', 'ignore'], ['homoglyphs', 'ignore'], ['installScripts', 'ignore'], ['invalidPackageJSON', 'ignore'], ['invisibleChars', 'ignore'], ['licenseChange', 'ignore'], ['licenseException', 'ignore'], ['longStrings', 'ignore'], ['majorRefactor', 'ignore'], ['manifestConfusion', 'ignore'], ['minifiedFile', 'ignore'], ['miscLicenseIssues', 'ignore'], ['missingAuthor', 'ignore'], ['missingDependency', 'ignore'], ['missingLicense', 'ignore'], ['missingTarball', 'ignore'], ['mixedLicense', 'ignore'], ['modifiedException', 'ignore'], ['modifiedLicense', 'ignore'], ['networkAccess', 'ignore'], ['newAuthor', 'ignore'], ['noAuthorData', 'ignore'], ['noBugTracker', 'ignore'], ['noLicenseFound', 'ignore'], ['noREADME', 'ignore'], ['noRepository', 'ignore'], ['noTests', 'ignore'], ['noV1', 'ignore'], ['noWebsite', 'ignore'], ['nonOSILicense', 'ignore'], ['nonSPDXLicense', 'ignore'], ['nonpermissiveLicense', 'ignore'], ['notice', 'ignore'], ['obfuscatedRequire', 'ignore'], ['peerDependency', 'ignore'], ['potentialVulnerability', 'ignore'], ['semverAnomaly', 'ignore'], ['shellAccess', 'ignore'], ['shellScriptOverride', 'ignore'], ['socketUpgradeAvailable', 'ignore'], ['suspiciousStarActivity', 'ignore'], ['suspiciousString', 'ignore'], ['trivialPackage', 'ignore'], ['typeModuleCompatibility', 'ignore'], ['uncaughtOptionalDependency', 'ignore'], ['unclearLicense', 'ignore'], ['unidentifiedLicense', 'ignore'], ['unmaintained', 'ignore'], ['unpublished', 'ignore'], ['unresolvedRequire', 'ignore'], ['unsafeCopyright', 'ignore'], ['unusedDependency', 'ignore'], ['urlStrings', 'ignore'], ['usesEval', 'ignore'], ['zeroWidth', 'ignore']]);
|
|
27
|
+
|
|
28
|
+
exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT;
|
|
29
|
+
exports.httpAgentNames = httpAgentNames;
|
|
30
|
+
exports.publicPolicy = publicPolicy;
|
package/dist/file-upload.js
CHANGED
|
@@ -1,49 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var events = require('node:events');
|
|
4
|
+
var node_fs = require('node:fs');
|
|
5
|
+
var path$1 = require('node:path');
|
|
6
|
+
var node_stream = require('node:stream');
|
|
7
|
+
var path = require('@socketsecurity/registry/lib/path');
|
|
8
|
+
var httpClient = require('./http-client.js');
|
|
9
|
+
|
|
9
10
|
/** @fileoverview File upload utilities for Socket API with multipart form data support. */
|
|
10
|
-
const node_events_1 = __importDefault(require("node:events"));
|
|
11
|
-
const node_fs_1 = require("node:fs");
|
|
12
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
-
const node_stream_1 = require("node:stream");
|
|
14
|
-
const path_1 = require("@socketsecurity/registry/lib/path");
|
|
15
|
-
const http_client_1 = require("./http-client");
|
|
16
11
|
/**
|
|
17
12
|
* Create multipart form-data body parts for file uploads.
|
|
18
13
|
* Converts file paths to readable streams with proper multipart headers.
|
|
19
14
|
*/
|
|
20
15
|
function createRequestBodyForFilepaths(filepaths, basePath) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return requestBody;
|
|
16
|
+
const requestBody = [];
|
|
17
|
+
for (const absPath of filepaths) {
|
|
18
|
+
const relPath = path.normalizePath(path$1.relative(basePath, absPath));
|
|
19
|
+
const filename = path$1.basename(absPath);
|
|
20
|
+
requestBody.push([`Content-Disposition: form-data; name="${relPath}"; filename="${filename}"\r\n`, 'Content-Type: application/octet-stream\r\n\r\n', node_fs.createReadStream(absPath, {
|
|
21
|
+
highWaterMark: 1024 * 1024
|
|
22
|
+
})]);
|
|
23
|
+
}
|
|
24
|
+
return requestBody;
|
|
32
25
|
}
|
|
26
|
+
|
|
33
27
|
/**
|
|
34
28
|
* Create multipart form-data body part for JSON data.
|
|
35
29
|
* Converts JSON object to readable stream with appropriate headers.
|
|
36
30
|
*/
|
|
37
31
|
function createRequestBodyForJson(jsonData, basename = 'data.json') {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
node_stream_1.Readable.from(JSON.stringify(jsonData), { highWaterMark: 1024 * 1024 }),
|
|
44
|
-
'\r\n',
|
|
45
|
-
];
|
|
32
|
+
const ext = path$1.extname(basename);
|
|
33
|
+
const name = path$1.basename(basename, ext);
|
|
34
|
+
return [`Content-Disposition: form-data; name="${name}"; filename="${basename}"\r\n` + 'Content-Type: application/json\r\n\r\n', node_stream.Readable.from(JSON.stringify(jsonData), {
|
|
35
|
+
highWaterMark: 1024 * 1024
|
|
36
|
+
}), '\r\n'];
|
|
46
37
|
}
|
|
38
|
+
|
|
47
39
|
/**
|
|
48
40
|
* Create and execute a multipart/form-data upload request.
|
|
49
41
|
* Streams large files efficiently with backpressure handling and early server validation.
|
|
@@ -51,101 +43,100 @@ function createRequestBodyForJson(jsonData, basename = 'data.json') {
|
|
|
51
43
|
* @throws {Error} When network errors occur or stream processing fails
|
|
52
44
|
*/
|
|
53
45
|
async function createUploadRequest(baseUrl, urlPath, requestBodyNoBoundaries, options) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
if (typeof part === 'string') {
|
|
103
|
-
/* c8 ignore next 5 - backpressure handling requires specific stream conditions */
|
|
104
|
-
if (!req.write(part)) {
|
|
105
|
-
// Wait for 'drain' if backpressure is signaled.
|
|
106
|
-
// eslint-disable-next-line no-await-in-loop
|
|
107
|
-
await node_events_1.default.once(req, 'drain');
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else if (typeof part?.pipe === 'function') {
|
|
111
|
-
// Stream data chunk-by-chunk with backpressure support.
|
|
112
|
-
const stream = part;
|
|
113
|
-
// eslint-disable-next-line no-await-in-loop
|
|
114
|
-
for await (const chunk of stream) {
|
|
115
|
-
/* c8 ignore next 3 - aborted state during streaming is difficult to test reliably */
|
|
116
|
-
if (aborted) {
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
/* c8 ignore next 3 - backpressure handling requires specific stream conditions */
|
|
120
|
-
if (!req.write(chunk)) {
|
|
121
|
-
await node_events_1.default.once(req, 'drain');
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
// Ensure trailing CRLF after file part.
|
|
125
|
-
/* c8 ignore next 4 - trailing CRLF backpressure handling is edge case */
|
|
126
|
-
if (!aborted && !req.write('\r\n')) {
|
|
127
|
-
// eslint-disable-next-line no-await-in-loop
|
|
128
|
-
await node_events_1.default.once(req, 'drain');
|
|
129
|
-
}
|
|
130
|
-
// Cleanup stream to free memory buffers.
|
|
131
|
-
if (typeof part.destroy === 'function') {
|
|
132
|
-
part.destroy();
|
|
133
|
-
}
|
|
134
|
-
/* c8 ignore next 3 - defensive check for non-string/stream types */
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
throw new TypeError('Expected "string" or "stream" type');
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
catch (e) {
|
|
142
|
-
req.destroy(e);
|
|
143
|
-
fail(e);
|
|
46
|
+
// This function constructs and sends a multipart/form-data HTTP POST request
|
|
47
|
+
// where each part is streamed to the server. It supports string payloads
|
|
48
|
+
// and readable streams (e.g., large file uploads).
|
|
49
|
+
|
|
50
|
+
// The body is streamed manually with proper backpressure support to avoid
|
|
51
|
+
// overwhelming Node.js memory (i.e., avoiding out-of-memory crashes for large inputs).
|
|
52
|
+
|
|
53
|
+
// We call `flushHeaders()` early to ensure headers are sent before body transmission
|
|
54
|
+
// begins. If the server rejects the request (e.g., bad org or auth), it will likely
|
|
55
|
+
// respond immediately. We listen for that response while still streaming the body.
|
|
56
|
+
//
|
|
57
|
+
// This protects against cases where the server closes the connection (EPIPE/ECONNRESET)
|
|
58
|
+
// mid-stream, which would otherwise cause hard-to-diagnose failures during file upload.
|
|
59
|
+
//
|
|
60
|
+
// Example failure this mitigates: `socket scan create --org badorg`
|
|
61
|
+
|
|
62
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
63
|
+
return await new Promise(async (pass, fail) => {
|
|
64
|
+
const boundary = `NodeMultipartBoundary${Date.now()}`;
|
|
65
|
+
const boundarySep = `--${boundary}\r\n`;
|
|
66
|
+
const finalBoundary = `--${boundary}--\r\n`;
|
|
67
|
+
const requestBody = [...requestBodyNoBoundaries.flatMap(part => [boundarySep, /* c8 ignore next - Array.isArray branch for part is defensive coding for edge cases. */
|
|
68
|
+
...(Array.isArray(part) ? part : [part])]), finalBoundary];
|
|
69
|
+
const url = new URL(urlPath, baseUrl);
|
|
70
|
+
const req = httpClient.getHttpModule(baseUrl).request(url, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
...options,
|
|
73
|
+
headers: {
|
|
74
|
+
...options?.headers,
|
|
75
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Send headers early to prompt server validation (auth, URL, quota, etc.).
|
|
80
|
+
req.flushHeaders();
|
|
81
|
+
|
|
82
|
+
// Concurrently wait for response while we stream body.
|
|
83
|
+
httpClient.getResponse(req).then(pass, fail);
|
|
84
|
+
let aborted = false;
|
|
85
|
+
req.on('error', () => aborted = true);
|
|
86
|
+
req.on('close', () => aborted = true);
|
|
87
|
+
try {
|
|
88
|
+
for (const part of requestBody) {
|
|
89
|
+
/* c8 ignore next 3 - aborted state is difficult to test reliably */
|
|
90
|
+
if (aborted) {
|
|
91
|
+
break;
|
|
144
92
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
93
|
+
if (typeof part === 'string') {
|
|
94
|
+
/* c8 ignore next 5 - backpressure handling requires specific stream conditions */
|
|
95
|
+
if (!req.write(part)) {
|
|
96
|
+
// Wait for 'drain' if backpressure is signaled.
|
|
97
|
+
// eslint-disable-next-line no-await-in-loop
|
|
98
|
+
await events.once(req, 'drain');
|
|
99
|
+
}
|
|
100
|
+
} else if (typeof part?.pipe === 'function') {
|
|
101
|
+
// Stream data chunk-by-chunk with backpressure support.
|
|
102
|
+
const stream = part;
|
|
103
|
+
// eslint-disable-next-line no-await-in-loop
|
|
104
|
+
for await (const chunk of stream) {
|
|
105
|
+
/* c8 ignore next 3 - aborted state during streaming is difficult to test reliably */
|
|
106
|
+
if (aborted) {
|
|
107
|
+
break;
|
|
148
108
|
}
|
|
109
|
+
/* c8 ignore next 3 - backpressure handling requires specific stream conditions */
|
|
110
|
+
if (!req.write(chunk)) {
|
|
111
|
+
await events.once(req, 'drain');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Ensure trailing CRLF after file part.
|
|
115
|
+
/* c8 ignore next 4 - trailing CRLF backpressure handling is edge case */
|
|
116
|
+
if (!aborted && !req.write('\r\n')) {
|
|
117
|
+
// eslint-disable-next-line no-await-in-loop
|
|
118
|
+
await events.once(req, 'drain');
|
|
119
|
+
}
|
|
120
|
+
// Cleanup stream to free memory buffers.
|
|
121
|
+
if (typeof part.destroy === 'function') {
|
|
122
|
+
part.destroy();
|
|
123
|
+
}
|
|
124
|
+
/* c8 ignore next 3 - defensive check for non-string/stream types */
|
|
125
|
+
} else {
|
|
126
|
+
throw new TypeError('Expected "string" or "stream" type');
|
|
149
127
|
}
|
|
150
|
-
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
req.destroy(e);
|
|
131
|
+
fail(e);
|
|
132
|
+
} finally {
|
|
133
|
+
if (!aborted) {
|
|
134
|
+
req.end();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
151
138
|
}
|
|
139
|
+
|
|
140
|
+
exports.createRequestBodyForFilepaths = createRequestBodyForFilepaths;
|
|
141
|
+
exports.createRequestBodyForJson = createRequestBodyForJson;
|
|
142
|
+
exports.createUploadRequest = createUploadRequest;
|
package/dist/http-client.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export declare function createDeleteRequest(baseUrl: string, urlPath: string, op
|
|
|
28
28
|
/**
|
|
29
29
|
* Create and execute an HTTP GET request.
|
|
30
30
|
* Returns the response stream for further processing.
|
|
31
|
+
* Performance tracking enabled with DEBUG=perf.
|
|
31
32
|
*
|
|
32
33
|
* @throws {Error} When network or timeout errors occur
|
|
33
34
|
*/
|
|
@@ -35,6 +36,7 @@ export declare function createGetRequest(baseUrl: string, urlPath: string, optio
|
|
|
35
36
|
/**
|
|
36
37
|
* Create and execute an HTTP request with JSON payload.
|
|
37
38
|
* Automatically sets appropriate content headers and serializes the body.
|
|
39
|
+
* Performance tracking enabled with DEBUG=perf.
|
|
38
40
|
*
|
|
39
41
|
* @throws {Error} When network or timeout errors occur
|
|
40
42
|
*/
|
|
@@ -61,6 +63,7 @@ export declare function getResponse(req: ClientRequest): Promise<IncomingMessage
|
|
|
61
63
|
/**
|
|
62
64
|
* Parse HTTP response body as JSON.
|
|
63
65
|
* Validates response status and handles empty responses gracefully.
|
|
66
|
+
* Performance tracking enabled with DEBUG=perf.
|
|
64
67
|
*
|
|
65
68
|
* @throws {ResponseError} When response has non-2xx status code
|
|
66
69
|
* @throws {SyntaxError} When response body contains invalid JSON
|
|
@@ -81,8 +84,8 @@ export declare function reshapeArtifactForPublicPolicy<T extends Record<string,
|
|
|
81
84
|
* Wraps any async HTTP function and retries on failure.
|
|
82
85
|
*
|
|
83
86
|
* @param fn - Async function to retry
|
|
84
|
-
* @param retries - Number of retry attempts (default:
|
|
85
|
-
* @param retryDelay - Initial delay in ms (default:
|
|
87
|
+
* @param retries - Number of retry attempts (default: 0, retries disabled)
|
|
88
|
+
* @param retryDelay - Initial delay in ms (default: 100)
|
|
86
89
|
* @returns Result of the function call
|
|
87
90
|
* @throws {Error} Last error if all retries exhausted
|
|
88
91
|
*/
|
|
@@ -91,23 +94,23 @@ export declare function withRetry<T>(fn: () => Promise<T>, retries?: number, ret
|
|
|
91
94
|
* Create GET request with automatic retry logic.
|
|
92
95
|
* Retries on network errors and 5xx responses.
|
|
93
96
|
*
|
|
94
|
-
* @param retries - Number of retry attempts (default:
|
|
95
|
-
* @param retryDelay - Initial delay in ms (default:
|
|
97
|
+
* @param retries - Number of retry attempts (default: 0, retries disabled)
|
|
98
|
+
* @param retryDelay - Initial delay in ms (default: 100)
|
|
96
99
|
*/
|
|
97
100
|
export declare function createGetRequestWithRetry(baseUrl: string, urlPath: string, options: RequestOptions, retries?: number, retryDelay?: number): Promise<IncomingMessage>;
|
|
98
101
|
/**
|
|
99
102
|
* Create DELETE request with automatic retry logic.
|
|
100
103
|
* Retries on network errors and 5xx responses.
|
|
101
104
|
*
|
|
102
|
-
* @param retries - Number of retry attempts (default:
|
|
103
|
-
* @param retryDelay - Initial delay in ms (default:
|
|
105
|
+
* @param retries - Number of retry attempts (default: 0, retries disabled)
|
|
106
|
+
* @param retryDelay - Initial delay in ms (default: 100)
|
|
104
107
|
*/
|
|
105
108
|
export declare function createDeleteRequestWithRetry(baseUrl: string, urlPath: string, options: RequestOptions, retries?: number, retryDelay?: number): Promise<IncomingMessage>;
|
|
106
109
|
/**
|
|
107
110
|
* Create request with JSON payload and automatic retry logic.
|
|
108
111
|
* Retries on network errors and 5xx responses.
|
|
109
112
|
*
|
|
110
|
-
* @param retries - Number of retry attempts (default:
|
|
111
|
-
* @param retryDelay - Initial delay in ms (default:
|
|
113
|
+
* @param retries - Number of retry attempts (default: 0, retries disabled)
|
|
114
|
+
* @param retryDelay - Initial delay in ms (default: 100)
|
|
112
115
|
*/
|
|
113
116
|
export declare function createRequestWithJsonAndRetry(method: SendMethod, baseUrl: string, urlPath: string, json: unknown, options: RequestOptions, retries?: number, retryDelay?: number): Promise<IncomingMessage>;
|