curl-wrap 2.0.1 → 2.1.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.
Files changed (4) hide show
  1. package/README.md +66 -0
  2. package/index.d.ts +18 -2
  3. package/index.js +364 -40
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -45,6 +45,9 @@ curl.headers({
45
45
  'User-Agent': 'curl-wrap/1.0',
46
46
  'Accept': 'application/json'
47
47
  });
48
+
49
+ // clear all headers
50
+ curl.clearHeaders();
48
51
  ```
49
52
 
50
53
  ### Setting Cookies
@@ -98,6 +101,9 @@ curl.impersonate('firefox');
98
101
  curl.impersonate('safari');
99
102
  curl.impersonate('safariMobile');
100
103
  curl.impersonate('edge');
104
+
105
+ // Or create a new instance with impersonation
106
+ const chromeCurl = Curl.impersonate('chrome');
101
107
  ```
102
108
 
103
109
  ### Setting Request Method
@@ -165,6 +171,66 @@ const response = await curl;
165
171
  console.log(response.stderr);
166
172
  ```
167
173
 
174
+ ### Buffer Response
175
+
176
+ ```js
177
+ curl.asBuffer();
178
+ const response = await curl;
179
+ console.log(response.body); // Buffer object instead of string
180
+ ```
181
+
182
+ ### Export as Curl Command
183
+
184
+ ```js
185
+ const curl = Curl.url('https://api.example.com')
186
+ .post()
187
+ .header('Content-Type', 'application/json')
188
+ .body({key: 'value'});
189
+
190
+ const curlCommand = await curl.exportAsCurl();
191
+ console.log(curlCommand);
192
+ // Output:
193
+ // curl 'https://api.example.com' \
194
+ // --request POST \
195
+ // --header 'content-type: application/json' \
196
+ // --data-raw '{"key":"value"}'
197
+ ```
198
+
199
+ ### Import from Curl Command
200
+
201
+ ```js
202
+ const curlCommand = `curl 'https://api.example.com' \
203
+ --request POST \
204
+ --header 'Content-Type: application/json' \
205
+ --header 'Authorization: Bearer token123' \
206
+ --cookie 'session=abc123; user=john' \
207
+ --data-raw '{"name":"John","age":30}'`;
208
+
209
+ const curl = Curl.fromCurl(curlCommand);
210
+ const response = await curl;
211
+ ```
212
+
213
+ ### Cloning Requests
214
+
215
+ ```js
216
+ const baseCurl = Curl.url('https://api.example.com')
217
+ .header('Authorization', 'Bearer token123')
218
+ .header('Content-Type', 'application/json');
219
+
220
+ // Clone and modify for different endpoints
221
+ const getUserCurl = baseCurl.clone()
222
+ .url('https://api.example.com/user')
223
+ .get();
224
+ const createUserCurl = baseCurl.clone()
225
+ .url('https://api.example.com/user')
226
+ .post()
227
+ .body({name: 'John'});
228
+
229
+ // Both requests share the same headers but have different URLs and methods
230
+ const userResponse = await getUserCurl;
231
+ const createResponse = await createUserCurl;
232
+ ```
233
+
168
234
  ### Method Chaining
169
235
 
170
236
  ```js
package/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { CookieJar } from "tough-cookie";
3
3
  interface CurlOptions {
4
4
  method?: string; // HTTP method (e.g., GET, POST)
5
5
  headers?: Record<string, string>; // Request headers
6
+ cookies?: Record<string, string>; // Request cookies
6
7
  body?: string | object | null; // Request body
7
8
  timeout?: number; // Timeout in milliseconds
8
9
  [key: string]: any; // Allow additional options
@@ -10,7 +11,7 @@ interface CurlOptions {
10
11
 
11
12
  interface CurlResponse {
12
13
  url: string;
13
- body: string; // Response body as a string
14
+ body: string | Buffer; // Response body as a string or Buffer
14
15
  headers: Record<string, string>; // Response headers
15
16
  statusCode: number; // HTTP status code
16
17
  status: number; // alias for .statusCode
@@ -50,6 +51,8 @@ export class Curl {
50
51
  static getGlobalCookieJar(): CookieJar;
51
52
 
52
53
  static hasCurlImpersonate(): boolean;
54
+ static impersonate(browser?: BrowserType): Curl;
55
+ static fromCurl(curlCommand: string): Curl;
53
56
 
54
57
  cliCommand(command: string): Curl;
55
58
  cliOptions(options: string | string[]): Curl;
@@ -61,6 +64,7 @@ export class Curl {
61
64
 
62
65
  header(headerName: string | object, headerValue?: string): Curl;
63
66
  headers(headers: object): Curl;
67
+ clearHeaders(): Curl;
64
68
 
65
69
  json(body?: object): Curl;
66
70
  body(body: any, contentType?: string): Curl;
@@ -78,10 +82,11 @@ export class Curl {
78
82
  cookieName: string | boolean | object,
79
83
  cookieValue?: string
80
84
  ): Curl;
81
- cookies(cookies: object | boolean): Curl;
85
+ cookies(cookies: object | boolean | string): Curl;
82
86
 
83
87
  globalCookies(options?: boolean | object): Curl;
84
88
  cookieJar(cookieJar: CookieJar, options?: { readOnly?: boolean }): Curl;
89
+ getCookieJar(): CookieJar | undefined;
85
90
  cookieFile(fileName: string, options?: object): Curl;
86
91
 
87
92
  timeout(timeout: number): Curl;
@@ -113,6 +118,12 @@ export class Curl {
113
118
 
114
119
  verbose(isVerbose?: boolean): Curl;
115
120
 
121
+ asBuffer(returnAsBuffer?: boolean): Curl;
122
+
123
+ clone(): Curl;
124
+
125
+ exportAsCurl(): Promise<string>;
126
+
116
127
  fetch(): Promise<CurlResponse>;
117
128
 
118
129
  then(
@@ -130,4 +141,9 @@ export class Curl {
130
141
  private options: any;
131
142
  private _fields: Record<string, any>;
132
143
  private _query: Record<string, any>;
144
+ private _cookies: Record<string, any>;
145
+ private _cookieJar?: CookieJar;
146
+ private _readCookieJar?: CookieJar;
147
+ private _cookieFileFn?: () => Promise<void>;
148
+ private _cookieFileFnRes?: () => Promise<void>;
133
149
  }
package/index.js CHANGED
@@ -42,10 +42,59 @@ function makeProxyUrl(proxy, options) {
42
42
  return uri.toString();
43
43
  }
44
44
 
45
+ /**
46
+ * Parse curl command string into arguments array
47
+ *
48
+ * @param {string} command
49
+ * @return {string[]}
50
+ */
51
+ function parseCommand(command) {
52
+ // Clean up the command - remove line breaks and extra spaces
53
+ command = command.replace(/\\\s*\n/g, ' ').replace(/\s+/g, ' ').trim();
54
+
55
+ const args = [];
56
+ let current = '';
57
+ let inQuotes = false;
58
+ let quoteChar = '';
59
+
60
+ for (let i = 0; i < command.length; i++) {
61
+ const char = command[i];
62
+ const nextChar = command[i + 1];
63
+
64
+ if ((char === '"' || char === "'") && !inQuotes) {
65
+ inQuotes = true;
66
+ quoteChar = char;
67
+ }
68
+ else if (char === quoteChar && inQuotes) {
69
+ inQuotes = false;
70
+ quoteChar = '';
71
+ }
72
+ else if (char === ' ' && !inQuotes) {
73
+ if (current.trim()) {
74
+ args.push(current.trim());
75
+ current = '';
76
+ }
77
+ }
78
+ else if (char === '\\' && nextChar === quoteChar && inQuotes) {
79
+ current += nextChar;
80
+ i++; // Skip next character
81
+ }
82
+ else {
83
+ current += char;
84
+ }
85
+ }
86
+
87
+ if (current.trim()) {
88
+ args.push(current.trim());
89
+ }
90
+
91
+ return args;
92
+ }
93
+
45
94
  class CurlResponse {
46
- constructor() {
95
+ constructor({body = ''} = {}) {
47
96
  this.url = '';
48
- this.body = '';
97
+ this.body = body;
49
98
  this.headers = {};
50
99
  this.statusCode = 0;
51
100
  this.ip = '';
@@ -81,6 +130,31 @@ class CurlResponse {
81
130
  }
82
131
  }
83
132
 
133
+ /**
134
+ * Parse cookies string into object
135
+ *
136
+ * @param {string} cookieStr
137
+ * @return {object}
138
+ */
139
+ function parseCookies(cookieStr) {
140
+ const cookies = {};
141
+ if (!cookieStr) return cookies;
142
+ const parts = cookieStr.split(';');
143
+
144
+ for (const part of parts) {
145
+ const equalIndex = part.indexOf('=');
146
+ if (equalIndex !== -1) {
147
+ const key = part.slice(0, equalIndex).trim();
148
+ const value = part.slice(equalIndex + 1).trim();
149
+ if (key && value) {
150
+ cookies[key] = value;
151
+ }
152
+ }
153
+ }
154
+
155
+ return cookies;
156
+ }
157
+
84
158
  class Curl {
85
159
  /**
86
160
  * Creates a new Curl object.
@@ -291,10 +365,14 @@ class Curl {
291
365
  return this;
292
366
  }
293
367
 
368
+ /**
369
+ * @typedef {"chrome"|"chromeMobile"|"edge"|"safari"|"safariMobile"|"firefox"} BrowserType
370
+ */
371
+
294
372
  /**
295
373
  * impersonate a browser
296
374
  *
297
- * @param {string} browser browser to impersonate (chrome / chromeMobile / edge / safari / safariMobile / firefox)
375
+ * @param {BrowserType} browser browser to impersonate
298
376
  * @return {Curl} self
299
377
  */
300
378
  impersonate(browser = 'chrome') {
@@ -566,6 +644,19 @@ class Curl {
566
644
  return this;
567
645
  }
568
646
 
647
+ /**
648
+ * @static
649
+ * impersonate a browser
650
+ *
651
+ * @param {BrowserType} browser browser to impersonate
652
+ * @return {Curl} self
653
+ */
654
+ static impersonate(browser = 'chrome') {
655
+ const curl = new this();
656
+ curl.impersonate(browser);
657
+ return curl;
658
+ }
659
+
569
660
  /**
570
661
  * Set or unset the followRedirect option for the connection.
571
662
  *
@@ -620,6 +711,16 @@ class Curl {
620
711
  return this;
621
712
  }
622
713
 
714
+ /**
715
+ * Clear all headers
716
+ *
717
+ * @return {Curl} self
718
+ */
719
+ clearHeaders() {
720
+ this.options.headers = {};
721
+ return this;
722
+ }
723
+
623
724
  /**
624
725
  * Set the content type as json
625
726
  * Optionally also set the body of the request.
@@ -739,19 +840,19 @@ class Curl {
739
840
  */
740
841
  cookie(cookieName, cookieValue) {
741
842
  if (cookieValue === undefined) {
742
- this.globalCookies(cookieName);
843
+ this.cookies(cookieName);
743
844
  }
744
845
  else if (typeof cookieName === 'string') {
745
- if (cookieValue === null || cookieValue === false) {
846
+ if (typeof cookieValue === 'string') {
847
+ this._cookies[cookieName] = cookieValue;
848
+ }
849
+ else if (cookieValue === null || cookieValue === false) {
746
850
  delete this._cookies[cookieName];
747
851
  }
748
852
  else {
749
- this._cookies[cookieName] = cookieValue;
853
+ this._cookies[cookieName] = JSON.stringify(cookieValue);
750
854
  }
751
855
  }
752
- else if (cookieName && typeof cookieName === 'object') {
753
- Object.assign(this._cookies, cookieName);
754
- }
755
856
 
756
857
  return this;
757
858
  }
@@ -760,7 +861,7 @@ class Curl {
760
861
  * Sets multiple cookies.
761
862
  * Can be used to enable global cookies, if cookies is set to true.
762
863
  *
763
- * @param {object|boolean} cookies object representing the cookies
864
+ * @param {object|boolean|string} cookies object representing the cookies
764
865
  * and their values as key:value pairs.
765
866
  * @return {Curl} self
766
867
  */
@@ -771,6 +872,10 @@ class Curl {
771
872
  else if (cookies && typeof cookies === 'object') {
772
873
  Object.assign(this._cookies, cookies);
773
874
  }
875
+ else if (typeof cookies === 'string') {
876
+ const cookies = parseCookies(cookieName);
877
+ Object.assign(this._cookies, cookies);
878
+ }
774
879
 
775
880
  return this;
776
881
  }
@@ -783,8 +888,8 @@ class Curl {
783
888
  */
784
889
  globalCookies(options = true) {
785
890
  if (options === false || options === null) {
786
- delete this.options.cookieJar;
787
- delete this.options.readCookieJar;
891
+ delete this._cookieJar;
892
+ delete this._readCookieJar;
788
893
  return this;
789
894
  }
790
895
 
@@ -804,15 +909,24 @@ class Curl {
804
909
  delete this._cookieFileFnRes;
805
910
 
806
911
  if (options.readOnly) {
807
- this.options.readCookieJar = cookieJar;
912
+ this._readCookieJar = cookieJar;
808
913
  }
809
914
  else {
810
- this.options.cookieJar = cookieJar;
915
+ this._cookieJar = cookieJar;
811
916
  }
812
917
 
813
918
  return this;
814
919
  }
815
920
 
921
+ /**
922
+ * Get the current cookie jar
923
+ *
924
+ * @return {CookieJar|undefined} the current cookie jar
925
+ */
926
+ getCookieJar() {
927
+ return this._cookieJar || this._readCookieJar;
928
+ }
929
+
816
930
  /**
817
931
  * Set the value of cookie jar based on a file (cookie store).
818
932
  *
@@ -822,10 +936,10 @@ class Curl {
822
936
  cookieFile(fileName, options = {}) {
823
937
  const setCookieJar = (cookieJar) => {
824
938
  if (options.readOnly) {
825
- this.options.readCookieJar = cookieJar;
939
+ this._readCookieJar = cookieJar;
826
940
  }
827
941
  else {
828
- this.options.cookieJar = cookieJar;
942
+ this._cookieJar = cookieJar;
829
943
  }
830
944
  };
831
945
 
@@ -843,7 +957,7 @@ class Curl {
843
957
 
844
958
  if (!options.readOnly) {
845
959
  this._cookieFileFnRes = async () => {
846
- const cookieJar = this.options.cookieJar;
960
+ const cookieJar = this._cookieJar;
847
961
  if (!cookieJar) return;
848
962
  try {
849
963
  const contents = JSON.stringify(cookieJar.toJSON());
@@ -1088,6 +1202,205 @@ class Curl {
1088
1202
  return this;
1089
1203
  }
1090
1204
 
1205
+ /**
1206
+ * Set if the body is to be returned as a buffer
1207
+ *
1208
+ * @param {boolean} [returnAsBuffer=true]
1209
+ * @return {Curl} self
1210
+ */
1211
+ asBuffer(returnAsBuffer = true) {
1212
+ this.options.asBuffer = returnAsBuffer;
1213
+ return this;
1214
+ }
1215
+
1216
+ /**
1217
+ * Create a clone of this Curl instance with the same options
1218
+ *
1219
+ * @return {Curl} new Curl instance with cloned options
1220
+ */
1221
+ clone() {
1222
+ const cloned = new this.constructor();
1223
+
1224
+ // Deep clone the options object (only serializable properties)
1225
+ cloned.options = JSON.parse(JSON.stringify(this.options));
1226
+
1227
+ // Copy non-serializable properties
1228
+ if (this._cookieJar) {
1229
+ cloned._cookieJar = this._cookieJar;
1230
+ }
1231
+ if (this._readCookieJar) {
1232
+ cloned._readCookieJar = this._readCookieJar;
1233
+ }
1234
+ if (this._cookieFileFn) {
1235
+ cloned._cookieFileFn = this._cookieFileFn;
1236
+ }
1237
+ if (this._cookieFileFnRes) {
1238
+ cloned._cookieFileFnRes = this._cookieFileFnRes;
1239
+ }
1240
+
1241
+ return cloned;
1242
+ }
1243
+
1244
+ /**
1245
+ * Export the current request as a curl command string
1246
+ *
1247
+ * @return {Promise<string>} curl command as a string
1248
+ */
1249
+ async exportAsCurl() {
1250
+ const cmd = this.options.cliCommand || 'curl';
1251
+ const args = await this.getCurlArgs();
1252
+ // Filter out internal options that shouldn't appear in exported commands
1253
+ const skipOptions = ['--silent', '--no-keepalive', '--keepalive', '--write-out', '--insecure', '--location'];
1254
+ const escape = arg => `'${arg.replace(/'/g, "'\"'\"'")}'`;
1255
+
1256
+ const url = args[0];
1257
+ const lines = [`${cmd} ${escape(url)}`];
1258
+ for (let i = 1; i < args.length; i++) {
1259
+ const arg = String(args[i]);
1260
+ const nextArg = String(args[i + 1] ?? '');
1261
+ const isNextArgValue = !nextArg.startsWith('--');
1262
+ if (isNextArgValue) {
1263
+ i++;
1264
+ }
1265
+ // Skip internal options and their values
1266
+ if (skipOptions.includes(arg)) continue;
1267
+ if (isNextArgValue) {
1268
+ const escapedNextArg = /[\s"'`&:;,><|(){}~^%#@!/=+\$\?\*\[\]]/.test(nextArg) ? escape(nextArg) : nextArg;
1269
+ lines.push(`${arg} ${escapedNextArg}`);
1270
+ }
1271
+ else {
1272
+ lines.push(arg);
1273
+ }
1274
+ }
1275
+
1276
+ return lines.join(' \\\n ');
1277
+ }
1278
+
1279
+ /**
1280
+ * @static
1281
+ * Create a new Curl instance from a curl command string
1282
+ *
1283
+ * @param {string} curlCommand curl command string to parse
1284
+ * @return {Curl} new Curl instance
1285
+ */
1286
+ static fromCurl(curlCommand) {
1287
+ const curl = new this();
1288
+ curl.options.headers = {};
1289
+
1290
+ // Parse the command into arguments
1291
+ const args = parseCommand(curlCommand);
1292
+
1293
+ let method;
1294
+ let body;
1295
+
1296
+ // Process arguments
1297
+ for (let i = 0; i < args.length; i++) {
1298
+ const arg = args[i];
1299
+ const nextArg = args[i + 1];
1300
+ const isNextArgValue = nextArg && !nextArg.startsWith('-');
1301
+
1302
+ if (i === 0 && !arg.startsWith('curl')) {
1303
+ // First argument should be the URL if no 'curl' command prefix
1304
+ curl.url(arg);
1305
+ }
1306
+ else if (i === 1 && args[0].startsWith('curl')) {
1307
+ // Second argument is URL when first is 'curl'
1308
+ curl.url(arg);
1309
+ }
1310
+ else if (arg === '--request' || arg === '-X') {
1311
+ if (!isNextArgValue) continue;
1312
+ method = nextArg;
1313
+ i++;
1314
+ }
1315
+ else if (arg === '--header' || arg === '-H') {
1316
+ if (!isNextArgValue) continue;
1317
+ const colonIndex = nextArg.indexOf(':');
1318
+ if (colonIndex !== -1) {
1319
+ const headerName = nextArg.slice(0, colonIndex).trim();
1320
+ const headerValue = nextArg.slice(colonIndex + 1).trim();
1321
+ curl.header(headerName, headerValue);
1322
+ }
1323
+ i++;
1324
+ }
1325
+ else if (arg === '--data' || arg === '--data-raw' || arg === '-d') {
1326
+ if (!isNextArgValue) continue;
1327
+ body = nextArg;
1328
+ i++;
1329
+ }
1330
+ else if (arg === '--cookie' || arg === '-b') {
1331
+ if (!isNextArgValue) continue;
1332
+ curl.header('cookie', nextArg);
1333
+ i++;
1334
+ }
1335
+ else if (arg === '--user-agent' || arg === '-A') {
1336
+ if (!isNextArgValue) continue;
1337
+ curl.userAgent(nextArg);
1338
+ i++;
1339
+ }
1340
+ else if (arg === '--referer' || arg === '-e') {
1341
+ if (!isNextArgValue) continue;
1342
+ curl.referer(nextArg);
1343
+ i++;
1344
+ }
1345
+ else if (arg === '--max-time' || arg === '-m') {
1346
+ if (!isNextArgValue) continue;
1347
+ const timeout = Number(nextArg);
1348
+ if (timeout > 0) curl.timeout(timeout);
1349
+ i++;
1350
+ }
1351
+ else if (arg === '--proxy' || arg === '-x') {
1352
+ if (!isNextArgValue) continue;
1353
+ curl.proxy(nextArg);
1354
+ i++;
1355
+ }
1356
+ else if (arg === '--compressed') {
1357
+ curl.compress(true);
1358
+ }
1359
+ else if (arg === '--location' || arg === '-L') {
1360
+ curl.followRedirect(true);
1361
+ }
1362
+ else if (arg === '--max-redirs') {
1363
+ if (!isNextArgValue) continue;
1364
+ const maxRedir = Math.floor(Number(nextArg));
1365
+ if (maxRedir > 0) curl.maxRedirects(maxRedir);
1366
+ i++;
1367
+ }
1368
+ else if (arg === '--verbose' || arg === '-v') {
1369
+ curl.verbose(true);
1370
+ }
1371
+ else if (arg.startsWith('--') || arg.startsWith('-')) {
1372
+ // Ignore internal options that shouldn't be imported
1373
+ const ignoreOptions = ['--silent', '--no-keepalive', '--keepalive', '--write-out', '--insecure'];
1374
+ if (ignoreOptions.includes(arg)) {
1375
+ // If the ignored option has a value, ignore it too
1376
+ if (isNextArgValue) {
1377
+ i++;
1378
+ }
1379
+ }
1380
+ else {
1381
+ // Handle unknown curl options by adding them as cliOptions
1382
+ if (isNextArgValue) {
1383
+ curl.cliOptions([arg, nextArg]);
1384
+ i++; // Skip next argument
1385
+ }
1386
+ else {
1387
+ curl.cliOptions(arg);
1388
+ }
1389
+ }
1390
+ }
1391
+ }
1392
+
1393
+ if (body) {
1394
+ curl.body(body);
1395
+ method = method || 'POST';
1396
+ }
1397
+ if (method) {
1398
+ curl.method(method);
1399
+ }
1400
+
1401
+ return curl;
1402
+ }
1403
+
1091
1404
  /**
1092
1405
  * Add the options 'fields' to the options body, form or qs
1093
1406
  * on the basis of the request method.
@@ -1167,7 +1480,7 @@ class Curl {
1167
1480
  await this._cookieFileFn();
1168
1481
  }
1169
1482
 
1170
- const cookieJar = options.readCookieJar || options.cookieJar;
1483
+ const cookieJar = this._readCookieJar || this._cookieJar;
1171
1484
  if (cookieJar) {
1172
1485
  const jarCookies = await cookieJar.getCookies(options.url);
1173
1486
  if (jarCookies) {
@@ -1203,19 +1516,12 @@ class Curl {
1203
1516
  '%{stderr}===<json>==={"json":%{json},"headers":%{header_json}}===</json>===',
1204
1517
  ];
1205
1518
 
1206
- if (body) {
1207
- args.push('--data-raw', body);
1208
- }
1209
-
1210
- const cookieHeader = await this.getCookieHeader();
1211
- if (cookieHeader) {
1212
- this.header('cookie', cookieHeader);
1519
+ const cliOptions = options.cliOptions;
1520
+ if (cliOptions) {
1521
+ args.push(...cliOptions);
1213
1522
  }
1214
1523
 
1215
- for (const [key, value] of Object.entries(options.headers)) {
1216
- args.push('--header', `${key}: ${value}`);
1217
- }
1218
- if (options.compress) {
1524
+ if (options.compress && !cliOptions?.includes('--compressed')) {
1219
1525
  args.push('--compressed');
1220
1526
  }
1221
1527
  if (options.proxy && options.useProxy !== false) {
@@ -1237,9 +1543,17 @@ class Curl {
1237
1543
  args.push('--verbose');
1238
1544
  }
1239
1545
 
1240
- const cliOptions = options.cliOptions;
1241
- if (cliOptions) {
1242
- args.push(...cliOptions);
1546
+ const cookieHeader = await this.getCookieHeader();
1547
+ if (cookieHeader) {
1548
+ this.header('cookie', cookieHeader);
1549
+ }
1550
+
1551
+ for (const [key, value] of Object.entries(options.headers)) {
1552
+ args.push('--header', `${key}: ${value}`);
1553
+ }
1554
+
1555
+ if (body) {
1556
+ args.push('--data-raw', body);
1243
1557
  }
1244
1558
 
1245
1559
  return args;
@@ -1247,18 +1561,28 @@ class Curl {
1247
1561
 
1248
1562
  async fetch() {
1249
1563
  const startTime = Date.now();
1250
- const cmd = this.options.cliCommand || 'curl';
1564
+ const options = this.options;
1565
+ const cmd = options.cliCommand || 'curl';
1251
1566
  const args = await this.getCurlArgs();
1252
1567
  const curl = spawn(cmd, args);
1253
- const cookieJar = this.options.cookieJar;
1568
+ const cookieJar = this._cookieJar;
1254
1569
 
1255
- let stdout = '';
1570
+ let stdout = options.asBuffer ? Buffer.from([]) : '';
1256
1571
  let stderr = '';
1257
- const response = new CurlResponse();
1572
+ const response = new CurlResponse({
1573
+ body: options.asBuffer ? Buffer.from([]) : '',
1574
+ });
1258
1575
  return new Promise((resolve, reject) => {
1259
- curl.stdout.on('data', (data) => {
1260
- stdout += data;
1261
- });
1576
+ if (options.asBuffer) {
1577
+ curl.stdout.on('data', (data) => {
1578
+ stdout = Buffer.concat([stdout, data]);
1579
+ });
1580
+ }
1581
+ else {
1582
+ curl.stdout.on('data', (data) => {
1583
+ stdout += data;
1584
+ });
1585
+ }
1262
1586
 
1263
1587
  curl.stderr.on('data', (data) => {
1264
1588
  stderr += data;
@@ -1272,7 +1596,7 @@ class Curl {
1272
1596
  curl.on('close', async (code) => {
1273
1597
  response.timeTaken = Date.now() - startTime;
1274
1598
  response.exitCode = code;
1275
- response.url = this.options.url;
1599
+ response.url = options.url;
1276
1600
  response.body = stdout;
1277
1601
  stderr = stderr.replace(/===<json>===(.*)===<\/json>===/s, (match, p1) => {
1278
1602
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "curl-wrap",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "Nodejs library that wraps curl command line",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",