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