create-request 1.0.0 → 1.1.0

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.
@@ -178,11 +178,16 @@ class RequestError extends Error {
178
178
  * Provides caching and conversion between different response formats.
179
179
  */
180
180
  class ResponseWrapper {
181
- constructor(response, url, method) {
181
+ constructor(response, url, method, graphQLOptions) {
182
182
  this.bodyUsed = false;
183
183
  this.response = response;
184
184
  this.url = url;
185
185
  this.method = method;
186
+ if (graphQLOptions) {
187
+ this.graphQLOptions = {
188
+ throwOnError: graphQLOptions.throwOnError,
189
+ };
190
+ }
186
191
  }
187
192
  // Wrapper properties
188
193
  get status() {
@@ -200,19 +205,51 @@ class ResponseWrapper {
200
205
  get raw() {
201
206
  return this.response;
202
207
  }
208
+ /**
209
+ * Check for GraphQL errors and throw if throwOnError is enabled
210
+ * @param data - The parsed JSON data
211
+ * @throws RequestError if GraphQL response contains errors and throwOnError is enabled
212
+ */
213
+ checkGraphQLErrors(data) {
214
+ var _a;
215
+ if (!((_a = this.graphQLOptions) === null || _a === void 0 ? void 0 : _a.throwOnError) || typeof data !== "object" || data === null)
216
+ return;
217
+ const responseData = data;
218
+ if (!Array.isArray(responseData.errors) || responseData.errors.length === 0)
219
+ return;
220
+ const errors = responseData.errors;
221
+ const errorMessages = errors.map(x => typeof x === "string" ? x : x && typeof x === "object" && "message" in x ? String(x.message || "Unknown error") : String(x));
222
+ const errorMessage = errorMessages.join(", ");
223
+ throw new RequestError(`GraphQL request failed with errors: ${errorMessage}`, this.url || "", this.method || "", {
224
+ status: this.response.status,
225
+ response: this.response,
226
+ });
227
+ }
203
228
  /**
204
229
  * Parse the response body as JSON
205
230
  * Caches the result for subsequent calls.
231
+ * If GraphQL options are set with throwOnError=true, will check for GraphQL errors and throw.
206
232
  *
207
233
  * @returns The parsed JSON data
208
- * @throws Error if the response has already been consumed in a different format
234
+ * @throws {RequestError} When the request fails, JSON parsing fails, GraphQL errors occur (if throwOnError enabled), or body is already consumed
209
235
  *
210
236
  * @example
211
237
  * const data = await response.getJson();
212
238
  * console.log(data.items);
239
+ *
240
+ * @example
241
+ * // Error handling - errors are always RequestError
242
+ * try {
243
+ * const data = await response.getJson();
244
+ * } catch (error) {
245
+ * if (error instanceof RequestError) {
246
+ * console.log(error.status, error.url, error.method);
247
+ * }
248
+ * }
213
249
  */
214
250
  async getJson() {
215
251
  if (this.jsonCache !== undefined) {
252
+ this.checkGraphQLErrors(this.jsonCache);
216
253
  return this.jsonCache;
217
254
  }
218
255
  if (this.bodyUsed) {
@@ -221,40 +258,43 @@ class ResponseWrapper {
221
258
  try {
222
259
  const parsed = JSON.parse(this.textCache);
223
260
  this.jsonCache = parsed;
261
+ this.checkGraphQLErrors(parsed);
224
262
  return parsed;
225
263
  }
226
- catch (e) {
227
- const errorMessage = e instanceof Error ? e.message : String(e);
228
- if (this.url && this.method) {
229
- throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url, this.method, {
230
- response: this.response,
231
- });
264
+ catch (error) {
265
+ // Re-throw RequestErrors from checkGraphQLErrors without wrapping
266
+ if (error instanceof RequestError) {
267
+ throw error;
232
268
  }
233
- throw new Error(`Invalid JSON: ${errorMessage}`);
269
+ const errorMessage = error instanceof Error ? error.message : String(error);
270
+ throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url || "", this.method || "", {
271
+ status: this.response.status,
272
+ response: this.response,
273
+ });
234
274
  }
235
275
  }
236
- if (this.url && this.method) {
237
- throw new RequestError("Body already consumed", this.url, this.method, {
238
- response: this.response,
239
- });
240
- }
241
- throw new Error("Body already consumed");
276
+ throw new RequestError("Body already consumed", this.url || "", this.method || "", {
277
+ status: this.response.status,
278
+ response: this.response,
279
+ });
242
280
  }
243
281
  this.bodyUsed = true;
244
282
  try {
245
283
  const parsed = await this.response.json();
246
284
  this.jsonCache = parsed;
285
+ this.checkGraphQLErrors(parsed);
247
286
  return parsed;
248
287
  }
249
- catch (e) {
250
- const errorMessage = e instanceof Error ? e.message : String(e);
251
- if (this.url && this.method) {
252
- throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url, this.method, {
253
- status: this.response.status,
254
- response: this.response,
255
- });
288
+ catch (error) {
289
+ // Re-throw RequestErrors from checkGraphQLErrors without wrapping
290
+ if (error instanceof RequestError) {
291
+ throw error;
256
292
  }
257
- throw e;
293
+ const errorMessage = error instanceof Error ? error.message : String(error);
294
+ throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url || "", this.method || "", {
295
+ status: this.response.status,
296
+ response: this.response,
297
+ });
258
298
  }
259
299
  }
260
300
  /**
@@ -263,7 +303,7 @@ class ResponseWrapper {
263
303
  * if the body has already been consumed in those formats.
264
304
  *
265
305
  * @returns The response text
266
- * @throws Error if the response has already been consumed in an incompatible format
306
+ * @throws {RequestError} When reading fails or the response has already been consumed in an incompatible format
267
307
  *
268
308
  * @example
269
309
  * const text = await response.getText();
@@ -286,20 +326,16 @@ class ResponseWrapper {
286
326
  }
287
327
  catch (e) {
288
328
  const errorMessage = e instanceof Error ? e.message : String(e);
289
- if (this.url && this.method) {
290
- throw new RequestError(`Cannot convert to text: ${errorMessage}`, this.url, this.method, {
291
- response: this.response,
292
- });
293
- }
294
- throw e;
329
+ throw new RequestError(`Cannot convert to text: ${errorMessage}`, this.url || "", this.method || "", {
330
+ status: this.response.status,
331
+ response: this.response,
332
+ });
295
333
  }
296
334
  }
297
- if (this.url && this.method) {
298
- throw new RequestError("Cannot convert to text", this.url, this.method, {
299
- response: this.response,
300
- });
301
- }
302
- throw new Error("Cannot convert to text");
335
+ throw new RequestError("Cannot convert to text", this.url || "", this.method || "", {
336
+ status: this.response.status,
337
+ response: this.response,
338
+ });
303
339
  }
304
340
  this.bodyUsed = true;
305
341
  try {
@@ -308,13 +344,10 @@ class ResponseWrapper {
308
344
  }
309
345
  catch (e) {
310
346
  const errorMessage = e instanceof Error ? e.message : String(e);
311
- if (this.url && this.method) {
312
- throw new RequestError(`Read failed: ${errorMessage}`, this.url, this.method, {
313
- status: this.response.status,
314
- response: this.response,
315
- });
316
- }
317
- throw e;
347
+ throw new RequestError(`Read failed: ${errorMessage}`, this.url || "", this.method || "", {
348
+ status: this.response.status,
349
+ response: this.response,
350
+ });
318
351
  }
319
352
  }
320
353
  /**
@@ -323,7 +356,7 @@ class ResponseWrapper {
323
356
  * if the body has already been consumed as text.
324
357
  *
325
358
  * @returns The response as a Blob
326
- * @throws Error if the response has already been consumed in an incompatible format
359
+ * @throws {RequestError} When reading fails or the response has already been consumed in an incompatible format
327
360
  *
328
361
  * @example
329
362
  * const blob = await response.getBlob();
@@ -339,12 +372,10 @@ class ResponseWrapper {
339
372
  this.blobCache = new Blob([this.textCache], { type: "text/plain" });
340
373
  return this.blobCache;
341
374
  }
342
- if (this.url && this.method) {
343
- throw new RequestError("Cannot convert to Blob", this.url, this.method, {
344
- response: this.response,
345
- });
346
- }
347
- throw new Error("Cannot convert to Blob");
375
+ throw new RequestError("Cannot convert to Blob", this.url || "", this.method || "", {
376
+ status: this.response.status,
377
+ response: this.response,
378
+ });
348
379
  }
349
380
  this.bodyUsed = true;
350
381
  try {
@@ -353,13 +384,10 @@ class ResponseWrapper {
353
384
  }
354
385
  catch (e) {
355
386
  const errorMessage = e instanceof Error ? e.message : String(e);
356
- if (this.url && this.method) {
357
- throw new RequestError(`Read failed: ${errorMessage}`, this.url, this.method, {
358
- status: this.response.status,
359
- response: this.response,
360
- });
361
- }
362
- throw e;
387
+ throw new RequestError(`Read failed: ${errorMessage}`, this.url || "", this.method || "", {
388
+ status: this.response.status,
389
+ response: this.response,
390
+ });
363
391
  }
364
392
  }
365
393
  /**
@@ -367,7 +395,7 @@ class ResponseWrapper {
367
395
  * This method consumes the body and should only be called once.
368
396
  *
369
397
  * @returns The response body as a ReadableStream or null
370
- * @throws Error if the response body has already been consumed
398
+ * @throws {RequestError} When the response body has already been consumed
371
399
  *
372
400
  * @example
373
401
  * const stream = response.getBody();
@@ -378,12 +406,10 @@ class ResponseWrapper {
378
406
  */
379
407
  getBody() {
380
408
  if (this.bodyUsed) {
381
- if (this.url && this.method) {
382
- throw new RequestError("Body already consumed", this.url, this.method, {
383
- response: this.response,
384
- });
385
- }
386
- throw new Error("Body already consumed");
409
+ throw new RequestError("Body already consumed", this.url || "", this.method || "", {
410
+ status: this.response.status,
411
+ response: this.response,
412
+ });
387
413
  }
388
414
  this.bodyUsed = true;
389
415
  return this.response.body;
@@ -394,6 +420,7 @@ class ResponseWrapper {
394
420
  *
395
421
  * @param selector - Optional function to extract and transform data
396
422
  * @returns A promise that resolves to the selected data
423
+ * @throws {RequestError} When the request fails, JSON parsing fails, or the selector throws an error
397
424
  *
398
425
  * @example
399
426
  * // Get full response
@@ -401,6 +428,16 @@ class ResponseWrapper {
401
428
  *
402
429
  * // Extract specific data
403
430
  * const users = await response.getData(data => data.results.users);
431
+ *
432
+ * @example
433
+ * // Error handling - errors are always RequestError
434
+ * try {
435
+ * const data = await response.getData();
436
+ * } catch (error) {
437
+ * if (error instanceof RequestError) {
438
+ * console.log(error.status, error.url, error.method);
439
+ * }
440
+ * }
404
441
  */
405
442
  async getData(selector) {
406
443
  try {
@@ -419,20 +456,15 @@ class ResponseWrapper {
419
456
  // Enhance selector errors with context
420
457
  if (selector) {
421
458
  const errorMessage = error instanceof Error ? error.message : String(error);
422
- if (this.url && this.method) {
423
- throw new RequestError(`Data selector failed: ${errorMessage}`, this.url, this.method, {
424
- response: this.response,
425
- });
426
- }
427
- throw new Error(`Data selector failed: ${errorMessage}`);
459
+ throw new RequestError(`Data selector failed: ${errorMessage}`, this.url || "", this.method || "", {
460
+ status: this.response.status,
461
+ response: this.response,
462
+ });
428
463
  }
429
464
  // If we get here and it's not a RequestError, wrap it
430
465
  // This should rarely happen as getJson() should throw RequestError
431
466
  const errorObj = error instanceof Error ? error : new Error(String(error));
432
- if (this.url && this.method) {
433
- throw RequestError.networkError(this.url, this.method, errorObj);
434
- }
435
- throw errorObj;
467
+ throw RequestError.networkError(this.url || "", this.method || "", errorObj);
436
468
  }
437
469
  }
438
470
  }
@@ -840,6 +872,13 @@ class BaseRequest {
840
872
  this.errorInterceptors = [];
841
873
  this.url = url;
842
874
  }
875
+ /**
876
+ * Get GraphQL options if set (only for BodyRequest subclasses)
877
+ * @returns GraphQL options or undefined
878
+ */
879
+ getGraphQLOptions() {
880
+ return undefined;
881
+ }
843
882
  /**
844
883
  * Creates a fluent API for setting enum-based options
845
884
  * Combines direct setter with convenience methods
@@ -925,14 +964,14 @@ class BaseRequest {
925
964
  *
926
965
  * @param timeout - The timeout in milliseconds
927
966
  * @returns The request instance for chaining
928
- * @throws Error if timeout is not a positive number
967
+ * @throws RequestError if timeout is not a positive number
929
968
  *
930
969
  * @example
931
970
  * request.withTimeout(5000); // 5 seconds timeout
932
971
  */
933
972
  withTimeout(timeout) {
934
973
  if (!Number.isFinite(timeout) || timeout <= 0)
935
- throw new Error("Timeout must be a positive number");
974
+ throw new RequestError("Timeout must be a positive number", this.url, this.method);
936
975
  this.requestOptions.timeout = timeout;
937
976
  return this;
938
977
  }
@@ -941,14 +980,14 @@ class BaseRequest {
941
980
  *
942
981
  * @param retries - Number of retry attempts before failing
943
982
  * @returns The request instance for chaining
944
- * @throws Error if retries is not a non-negative integer
983
+ * @throws RequestError if retries is not a non-negative integer
945
984
  *
946
985
  * @example
947
986
  * request.withRetries(3); // Retry up to 3 times
948
987
  */
949
988
  withRetries(retries) {
950
989
  if (!Number.isInteger(retries) || retries < 0)
951
- throw new Error("Retry count must be a non-negative integer");
990
+ throw new RequestError("Retry count must be a non-negative integer", this.url, this.method);
952
991
  this.requestOptions.retries = retries;
953
992
  return this;
954
993
  }
@@ -1155,7 +1194,7 @@ class BaseRequest {
1155
1194
  if (typeof Buffer !== "undefined")
1156
1195
  return Buffer.from(str).toString("base64");
1157
1196
  // Fallback (should never happen in modern environments)
1158
- throw new Error("Base64 encoding is not supported");
1197
+ throw new RequestError("Base64 encoding is not supported", this.url, this.method);
1159
1198
  }
1160
1199
  /**
1161
1200
  * Sets the bearer token for authentication
@@ -1336,9 +1375,20 @@ class BaseRequest {
1336
1375
  * Execute the request and parse the response as JSON
1337
1376
  *
1338
1377
  * @returns A promise that resolves to the parsed JSON data
1378
+ * @throws {RequestError} When the request fails, JSON parsing fails, GraphQL errors occur (if throwOnError enabled), or body is already consumed
1339
1379
  *
1340
1380
  * @example
1341
1381
  * const users = await request.getJson<User[]>();
1382
+ *
1383
+ * @example
1384
+ * // Error handling - errors are always RequestError
1385
+ * try {
1386
+ * const data = await request.getJson();
1387
+ * } catch (error) {
1388
+ * if (error instanceof RequestError) {
1389
+ * console.log(error.status, error.url, error.method);
1390
+ * }
1391
+ * }
1342
1392
  */
1343
1393
  async getJson() {
1344
1394
  const response = await this.getResponse();
@@ -1386,6 +1436,7 @@ class BaseRequest {
1386
1436
  *
1387
1437
  * @param selector - Optional function to extract and transform data
1388
1438
  * @returns A promise that resolves to the selected data
1439
+ * @throws {RequestError} When the request fails, JSON parsing fails, or the selector throws an error
1389
1440
  *
1390
1441
  * @example
1391
1442
  * // Get full response
@@ -1393,6 +1444,16 @@ class BaseRequest {
1393
1444
  *
1394
1445
  * // Extract specific data
1395
1446
  * const users = await request.getData(data => data.results.users);
1447
+ *
1448
+ * @example
1449
+ * // Error handling - errors are always RequestError
1450
+ * try {
1451
+ * const data = await request.getData();
1452
+ * } catch (error) {
1453
+ * if (error instanceof RequestError) {
1454
+ * console.log(error.status, error.url, error.method);
1455
+ * }
1456
+ * }
1396
1457
  */
1397
1458
  async getData(selector) {
1398
1459
  const response = await this.getResponse();
@@ -1442,7 +1503,8 @@ class BaseRequest {
1442
1503
  * @returns The URL with query parameters appended
1443
1504
  */
1444
1505
  formatUrlWithQueryParams(url) {
1445
- if (!this.queryParams.toString()) {
1506
+ const queryString = this.queryParams.toString();
1507
+ if (!queryString) {
1446
1508
  return url;
1447
1509
  }
1448
1510
  try {
@@ -1458,7 +1520,7 @@ class BaseRequest {
1458
1520
  // Handle relative URLs
1459
1521
  const hasExistingParams = url.includes("?");
1460
1522
  const separator = hasExistingParams ? "&" : "?";
1461
- return `${url}${separator}${this.queryParams.toString()}`;
1523
+ return `${url}${separator}${queryString}`;
1462
1524
  }
1463
1525
  }
1464
1526
  /**
@@ -1507,8 +1569,7 @@ class BaseRequest {
1507
1569
  }
1508
1570
  catch (error) {
1509
1571
  const errorMessage = error instanceof Error ? error.message : String(error);
1510
- // Use RequestError when we have request context
1511
- throw new RequestError(`Interceptor failed: ${errorMessage}`, currentConfig.url, currentConfig.method);
1572
+ throw new RequestError(`Request interceptor failed: ${errorMessage}`, currentConfig.url, currentConfig.method);
1512
1573
  }
1513
1574
  }
1514
1575
  return currentConfig;
@@ -1530,12 +1591,9 @@ class BaseRequest {
1530
1591
  }
1531
1592
  catch (error) {
1532
1593
  const errorMessage = error instanceof Error ? error.message : String(error);
1533
- // Use RequestError when we have response context (url/method from ResponseWrapper)
1534
- if (currentResponse.url && currentResponse.method) {
1535
- throw new RequestError(`Interceptor failed: ${errorMessage}`, currentResponse.url, currentResponse.method);
1536
- }
1537
- // Fallback to generic Error if no context available (shouldn't happen in practice)
1538
- throw new Error(`Interceptor failed: ${errorMessage}`);
1594
+ const url = currentResponse.url || "";
1595
+ const method = currentResponse.method || "";
1596
+ throw new RequestError(`Response interceptor failed: ${errorMessage}`, url, method);
1539
1597
  }
1540
1598
  }
1541
1599
  return currentResponse;
@@ -1569,11 +1627,16 @@ class BaseRequest {
1569
1627
  const errorMessage = interceptorError instanceof Error ? interceptorError.message : String(interceptorError);
1570
1628
  // Always wrap in RequestError when we have context
1571
1629
  if (currentError instanceof RequestError) {
1572
- currentError = new RequestError(`Error interceptor ${i + 1} failed: ${errorMessage}`, currentError.url, currentError.method);
1630
+ currentError = new RequestError(`Error interceptor ${i + 1} failed: ${errorMessage}`, currentError.url, currentError.method, {
1631
+ status: currentError.status,
1632
+ response: currentError.response,
1633
+ });
1573
1634
  }
1574
1635
  else if (currentError instanceof ResponseWrapper && currentError.url && currentError.method) {
1575
1636
  // If it's a ResponseWrapper, we can still create a proper RequestError from its context
1576
- currentError = new RequestError(`Error interceptor ${i + 1} failed: ${errorMessage}`, currentError.url, currentError.method);
1637
+ currentError = new RequestError(`Error interceptor ${i + 1} failed: ${errorMessage}`, currentError.url, currentError.method, {
1638
+ status: currentError.status,
1639
+ });
1577
1640
  }
1578
1641
  else {
1579
1642
  // Last resort: if we have no context at all, use the original error's context
@@ -1695,7 +1758,8 @@ class BaseRequest {
1695
1758
  const interceptorResult = await this.runRequestInterceptors(requestConfig);
1696
1759
  // If interceptor returned a Response, short-circuit and wrap it
1697
1760
  if (interceptorResult instanceof Response) {
1698
- const wrappedResponse = new ResponseWrapper(interceptorResult, this.url, this.method);
1761
+ const graphQLOptions = this.getGraphQLOptions();
1762
+ const wrappedResponse = new ResponseWrapper(interceptorResult, this.url, this.method, graphQLOptions);
1699
1763
  return await this.runResponseInterceptors(wrappedResponse);
1700
1764
  }
1701
1765
  // Update fetchOptions with interceptor modifications
@@ -1731,7 +1795,8 @@ class BaseRequest {
1731
1795
  if (!response.ok) {
1732
1796
  throw RequestError.fromResponse(response, url, method);
1733
1797
  }
1734
- const wrappedResponse = new ResponseWrapper(response, url, method);
1798
+ const graphQLOptions = this.getGraphQLOptions();
1799
+ const wrappedResponse = new ResponseWrapper(response, url, method, graphQLOptions);
1735
1800
  return await this.runResponseInterceptors(wrappedResponse);
1736
1801
  }
1737
1802
  catch (error) {
@@ -1764,6 +1829,7 @@ class BaseRequest {
1764
1829
  class BodyRequest extends BaseRequest {
1765
1830
  constructor(url) {
1766
1831
  super(url);
1832
+ this.graphQLOptions = undefined;
1767
1833
  }
1768
1834
  /**
1769
1835
  * Sets the body of the request
@@ -1786,7 +1852,8 @@ class BodyRequest extends BaseRequest {
1786
1852
  JSON.stringify(body);
1787
1853
  }
1788
1854
  catch (error) {
1789
- throw new RequestError(`Stringify failed: ${String(error)}`, this.url, this.method);
1855
+ const errorMessage = error instanceof Error ? error.message : String(error);
1856
+ throw new RequestError(`JSON stringify failed: ${errorMessage}`, this.url, this.method);
1790
1857
  }
1791
1858
  }
1792
1859
  else {
@@ -1800,6 +1867,7 @@ class BodyRequest extends BaseRequest {
1800
1867
  *
1801
1868
  * @param query - The GraphQL query or mutation string
1802
1869
  * @param variables - Optional variables object to pass with the query
1870
+ * @param options - Optional GraphQL-specific options
1803
1871
  * @returns The request instance for chaining
1804
1872
  *
1805
1873
  * @example
@@ -1809,13 +1877,18 @@ class BodyRequest extends BaseRequest {
1809
1877
  * @example
1810
1878
  * const request = new PostRequest('/graphql')
1811
1879
  * .withGraphQL('mutation { createUser(name: $name) { id } }', { name: 'John' });
1880
+ *
1881
+ * @example
1882
+ * // Throw an error if the GraphQL response contains errors
1883
+ * const request = new PostRequest('/graphql')
1884
+ * .withGraphQL('query { user { id } }', undefined, { throwOnError: true });
1812
1885
  */
1813
- withGraphQL(query, variables) {
1814
- if (typeof query !== "string" || query.trim().length === 0) {
1886
+ withGraphQL(query, variables, options) {
1887
+ if (typeof query !== "string" || query.length === 0) {
1815
1888
  throw new RequestError("Invalid GraphQL query", this.url, this.method);
1816
1889
  }
1817
1890
  const graphQLBody = {
1818
- query: query.trim(),
1891
+ query: query,
1819
1892
  };
1820
1893
  if (variables !== undefined) {
1821
1894
  if (typeof variables !== "object" || variables === null || Array.isArray(variables)) {
@@ -1823,12 +1896,24 @@ class BodyRequest extends BaseRequest {
1823
1896
  }
1824
1897
  graphQLBody.variables = variables;
1825
1898
  }
1899
+ // Store GraphQL options if provided
1900
+ if (options !== undefined) {
1901
+ if (typeof options !== "object" || options === null || Array.isArray(options)) {
1902
+ throw new RequestError("Invalid GraphQL options", this.url, this.method);
1903
+ }
1904
+ // Store only the known GraphQL options properties
1905
+ const opts = options;
1906
+ this.graphQLOptions = {
1907
+ throwOnError: typeof opts.throwOnError === "boolean" ? opts.throwOnError : undefined,
1908
+ };
1909
+ }
1826
1910
  // Validate JSON is stringifiable early
1827
1911
  try {
1828
1912
  JSON.stringify(graphQLBody);
1829
1913
  }
1830
1914
  catch (error) {
1831
- throw new RequestError(`Stringify failed: ${String(error)}`, this.url, this.method);
1915
+ const errorMessage = error instanceof Error ? error.message : String(error);
1916
+ throw new RequestError(`JSON stringify failed: ${errorMessage}`, this.url, this.method);
1832
1917
  }
1833
1918
  this.body = graphQLBody;
1834
1919
  this.bodyType = BodyType.JSON;
@@ -1851,6 +1936,13 @@ class BodyRequest extends BaseRequest {
1851
1936
  this.withContentType(contentType);
1852
1937
  }
1853
1938
  }
1939
+ /**
1940
+ * Get the GraphQL options if set
1941
+ * @returns The GraphQL options or undefined
1942
+ */
1943
+ getGraphQLOptions() {
1944
+ return this.graphQLOptions;
1945
+ }
1854
1946
  /**
1855
1947
  * Execute the request and return the ResponseWrapper
1856
1948
  * Overrides the base implementation to add body handling