create-request 1.4.3-rc.3 → 1.5.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.
@@ -144,8 +144,8 @@ class RequestError extends Error {
144
144
  this.method = method;
145
145
  this.status = options.status;
146
146
  this.response = options.response;
147
- this.isTimeout = options.isTimeout;
148
- this.isAborted = options.isAborted;
147
+ this.isTimeout = !!options.isTimeout;
148
+ this.isAborted = !!options.isAborted;
149
149
  // For better stack traces in modern environments
150
150
  if (Error.captureStackTrace) {
151
151
  Error.captureStackTrace(this, RequestError);
@@ -167,7 +167,7 @@ class RequestError extends Error {
167
167
  * ```
168
168
  */
169
169
  static timeout(url, method, timeoutMs) {
170
- return new RequestError(`Timeout ${timeoutMs}ms`, url, method, {
170
+ return new RequestError(`Timeout:${timeoutMs}`, url, method, {
171
171
  isTimeout: true,
172
172
  });
173
173
  }
@@ -246,16 +246,16 @@ class RequestError extends Error {
246
246
  // Check for connection errors (but not timeout errors)
247
247
  const isConnectionError = !isTimeoutError && (errorCode === "ECONNREFUSED" || errorCode === "ECONNRESET" || stack.includes("ECONNREFUSED") || stack.includes("connect"));
248
248
  if (isTimeoutError) {
249
- message = `Timeout ${url}`;
249
+ message = `Timeout:${url}`;
250
250
  }
251
251
  else if (isDnsError) {
252
- message = `DNS error ${url}`;
252
+ message = `DNS:${url}`;
253
253
  }
254
254
  else if (isConnectionError) {
255
- message = `Connection refused ${url}`;
255
+ message = `Conn:${url}`;
256
256
  }
257
257
  else {
258
- message = `Network error ${url}`;
258
+ message = `Net:${url}`;
259
259
  }
260
260
  }
261
261
  const error = new RequestError(message, url, method, {
@@ -365,7 +365,7 @@ class ResponseWrapper {
365
365
  */
366
366
  checkBodyNotConsumed() {
367
367
  if (this.response.bodyUsed) {
368
- throw new RequestError("Body already consumed", this.url || "", this.method || "", {
368
+ throw new RequestError("Body used", this.url || "", this.method || "", {
369
369
  status: this.response.status,
370
370
  response: this.response,
371
371
  });
@@ -407,7 +407,7 @@ class ResponseWrapper {
407
407
  return String(x);
408
408
  });
409
409
  const errorMessage = errorMessages.join(", ");
410
- throw new RequestError(`GraphQL errors: ${errorMessage}`, this.url || "", this.method || "", {
410
+ throw new RequestError(`GQL: ${errorMessage}`, this.url || "", this.method || "", {
411
411
  status: this.response.status,
412
412
  response: this.response,
413
413
  });
@@ -447,8 +447,7 @@ class ResponseWrapper {
447
447
  if (error instanceof RequestError) {
448
448
  throw error;
449
449
  }
450
- const errorMessage = error instanceof Error ? error.message : String(error);
451
- throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url || "", this.method || "", {
450
+ throw new RequestError(`Bad JSON: ${error instanceof Error ? error.message : String(error)}`, this.url || "", this.method || "", {
452
451
  status: this.response.status,
453
452
  response: this.response,
454
453
  });
@@ -477,8 +476,7 @@ class ResponseWrapper {
477
476
  return text;
478
477
  }
479
478
  catch (e) {
480
- const errorMessage = e instanceof Error ? e.message : String(e);
481
- throw new RequestError(`Read failed: ${errorMessage}`, this.url || "", this.method || "", {
479
+ throw new RequestError(`Read: ${e instanceof Error ? e.message : String(e)}`, this.url || "", this.method || "", {
482
480
  status: this.response.status,
483
481
  response: this.response,
484
482
  });
@@ -509,8 +507,7 @@ class ResponseWrapper {
509
507
  return blob;
510
508
  }
511
509
  catch (e) {
512
- const errorMessage = e instanceof Error ? e.message : String(e);
513
- throw new RequestError(`Read failed: ${errorMessage}`, this.url || "", this.method || "", {
510
+ throw new RequestError(`Read: ${e instanceof Error ? e.message : String(e)}`, this.url || "", this.method || "", {
514
511
  status: this.response.status,
515
512
  response: this.response,
516
513
  });
@@ -542,8 +539,7 @@ class ResponseWrapper {
542
539
  return arrayBuffer;
543
540
  }
544
541
  catch (e) {
545
- const errorMessage = e instanceof Error ? e.message : String(e);
546
- throw new RequestError(`Read failed: ${errorMessage}`, this.url || "", this.method || "", {
542
+ throw new RequestError(`Read: ${e instanceof Error ? e.message : String(e)}`, this.url || "", this.method || "", {
547
543
  status: this.response.status,
548
544
  response: this.response,
549
545
  });
@@ -609,8 +605,7 @@ class ResponseWrapper {
609
605
  }
610
606
  // Enhance selector errors with context
611
607
  if (selector) {
612
- const errorMessage = error instanceof Error ? error.message : String(error);
613
- throw new RequestError(`Data selector failed: ${errorMessage}`, this.url || "", this.method || "", {
608
+ throw new RequestError(`Selector: ${error instanceof Error ? error.message : String(error)}`, this.url || "", this.method || "", {
614
609
  status: this.response.status,
615
610
  response: this.response,
616
611
  });
@@ -1056,10 +1051,11 @@ class BaseRequest {
1056
1051
  return Object.assign(callable, fluent);
1057
1052
  }
1058
1053
  validateUrl(url) {
1054
+ const errorMessage = "Bad URL";
1059
1055
  if (!url?.trim())
1060
- throw new RequestError("Invalid URL", url, this.method);
1056
+ throw new RequestError(errorMessage, url, this.method);
1061
1057
  if (url.includes("\0") || url.includes("\r") || url.includes("\n")) {
1062
- throw new RequestError("Invalid URL", url, this.method);
1058
+ throw new RequestError(errorMessage, url, this.method);
1063
1059
  }
1064
1060
  const trimmed = url.trim();
1065
1061
  if (/^https?:\/\//.test(trimmed)) {
@@ -1067,7 +1063,7 @@ class BaseRequest {
1067
1063
  new URL(trimmed);
1068
1064
  }
1069
1065
  catch {
1070
- throw new RequestError("Invalid URL", trimmed, this.method);
1066
+ throw new RequestError(errorMessage, trimmed, this.method);
1071
1067
  }
1072
1068
  }
1073
1069
  }
@@ -1123,7 +1119,7 @@ class BaseRequest {
1123
1119
  */
1124
1120
  withTimeout(timeout) {
1125
1121
  if (!Number.isFinite(timeout) || timeout <= 0)
1126
- throw new RequestError("Invalid timeout", this.url, this.method);
1122
+ throw new RequestError("Bad timeout", this.url, this.method);
1127
1123
  this.requestOptions.timeout = timeout;
1128
1124
  return this;
1129
1125
  }
@@ -1162,24 +1158,24 @@ class BaseRequest {
1162
1158
  withRetries(retries) {
1163
1159
  if (typeof retries === "number") {
1164
1160
  if (!Number.isInteger(retries) || retries < 0) {
1165
- throw new RequestError(`Invalid retries: ${retries}`, this.url, this.method);
1161
+ throw new RequestError(`Bad retries: ${retries}`, this.url, this.method);
1166
1162
  }
1167
1163
  this.requestOptions.retries = retries;
1168
1164
  }
1169
1165
  else {
1170
1166
  // Validate RetryConfig
1171
1167
  if (!Number.isInteger(retries.attempts) || retries.attempts < 0) {
1172
- throw new RequestError(`Invalid attempts: ${retries.attempts}`, this.url, this.method);
1168
+ throw new RequestError(`Bad attempts: ${retries.attempts}`, this.url, this.method);
1173
1169
  }
1174
1170
  // Validate delay if provided
1175
1171
  if (retries.delay !== undefined) {
1176
1172
  if (typeof retries.delay === "number") {
1177
1173
  if (!Number.isFinite(retries.delay) || retries.delay < 0) {
1178
- throw new RequestError(`Invalid delay: ${retries.delay}`, this.url, this.method);
1174
+ throw new RequestError(`Bad delay: ${retries.delay}`, this.url, this.method);
1179
1175
  }
1180
1176
  }
1181
1177
  else if (typeof retries.delay !== "function") {
1182
- throw new RequestError(`Invalid delay: ${typeof retries.delay}`, this.url, this.method);
1178
+ throw new RequestError(`Bad delay: ${typeof retries.delay}`, this.url, this.method);
1183
1179
  }
1184
1180
  }
1185
1181
  this.requestOptions.retries = retries;
@@ -1662,7 +1658,7 @@ class BaseRequest {
1662
1658
  if (typeof Buffer !== "undefined")
1663
1659
  return Buffer.from(str).toString("base64");
1664
1660
  // Fallback (should never happen in modern environments)
1665
- throw new RequestError("Encoding not supported", this.url, this.method);
1661
+ throw new RequestError("No encoder", this.url, this.method);
1666
1662
  }
1667
1663
  /**
1668
1664
  * Sets a Bearer token for authentication.
@@ -1946,6 +1942,24 @@ class BaseRequest {
1946
1942
  const response = await this.getResponse();
1947
1943
  return response.getBlob();
1948
1944
  }
1945
+ /**
1946
+ * Execute the request and get the response body as an ArrayBuffer.
1947
+ * Useful for processing binary data at a low level.
1948
+ *
1949
+ * @returns A promise that resolves to the response body as an ArrayBuffer
1950
+ * @throws {RequestError} When the request fails or reading the response fails
1951
+ *
1952
+ * @example
1953
+ * ```typescript
1954
+ * const buffer = await request.getArrayBuffer();
1955
+ * const uint8Array = new Uint8Array(buffer);
1956
+ * // Process the binary data
1957
+ * ```
1958
+ */
1959
+ async getArrayBuffer() {
1960
+ const response = await this.getResponse();
1961
+ return response.getArrayBuffer();
1962
+ }
1949
1963
  /**
1950
1964
  * Execute the request and get the response body as a ReadableStream.
1951
1965
  * Note: Unlike other methods, streams cannot be cached. The body can only be consumed once.
@@ -2081,7 +2095,7 @@ class BaseRequest {
2081
2095
  const delay = typeof retriesConfig.delay === "function" ? retriesConfig.delay({ attempt: attempt + 1, error: requestError }) : retriesConfig.delay;
2082
2096
  // Validate delay result
2083
2097
  if (typeof delay !== "number" || !Number.isFinite(delay) || delay < 0) {
2084
- throw new RequestError(`Invalid delay: ${delay}`, url, method);
2098
+ throw new RequestError(`Bad delay: ${delay}`, url, method);
2085
2099
  }
2086
2100
  // Wait for the delay
2087
2101
  if (delay > 0) {
@@ -2112,8 +2126,7 @@ class BaseRequest {
2112
2126
  currentConfig = result;
2113
2127
  }
2114
2128
  catch (error) {
2115
- const errorMessage = error instanceof Error ? error.message : String(error);
2116
- throw new RequestError(`Req Interceptor failed: ${errorMessage}`, currentConfig.url, currentConfig.method);
2129
+ throw new RequestError(`ReqI: ${error instanceof Error ? error.message : String(error)}`, currentConfig.url, currentConfig.method);
2117
2130
  }
2118
2131
  }
2119
2132
  return currentConfig;
@@ -2127,17 +2140,14 @@ class BaseRequest {
2127
2140
  const globalConfig = Config.getInstance();
2128
2141
  const globalInterceptors = globalConfig.getResponseInterceptors();
2129
2142
  // Per-request in order, then global in reverse
2130
- const allInterceptors = [...this.responseInterceptors, ...globalInterceptors.reverse()];
2143
+ const allInterceptors = [...this.responseInterceptors, ...[...globalInterceptors].reverse()];
2131
2144
  let currentResponse = response;
2132
2145
  for (let i = 0; i < allInterceptors.length; i++) {
2133
2146
  try {
2134
2147
  currentResponse = await allInterceptors[i](currentResponse);
2135
2148
  }
2136
2149
  catch (error) {
2137
- const errorMessage = error instanceof Error ? error.message : String(error);
2138
- const url = currentResponse.url || "";
2139
- const method = currentResponse.method || "";
2140
- throw new RequestError(`Res Interceptor failed: ${errorMessage}`, url, method);
2150
+ throw new RequestError(`ResI: ${error instanceof Error ? error.message : String(error)}`, currentResponse.url || "", currentResponse.method || "");
2141
2151
  }
2142
2152
  }
2143
2153
  return currentResponse;
@@ -2151,7 +2161,7 @@ class BaseRequest {
2151
2161
  const globalConfig = Config.getInstance();
2152
2162
  const globalInterceptors = globalConfig.getErrorInterceptors();
2153
2163
  // Per-request in order, then global in reverse
2154
- const allInterceptors = [...this.errorInterceptors, ...globalInterceptors.reverse()];
2164
+ const allInterceptors = [...this.errorInterceptors, ...[...globalInterceptors].reverse()];
2155
2165
  let currentError = error;
2156
2166
  for (let i = 0; i < allInterceptors.length; i++) {
2157
2167
  try {
@@ -2168,10 +2178,10 @@ class BaseRequest {
2168
2178
  currentError = interceptorError;
2169
2179
  }
2170
2180
  else {
2171
- const errorMessage = interceptorError instanceof Error ? interceptorError.message : String(interceptorError);
2181
+ const em = interceptorError instanceof Error ? interceptorError.message : String(interceptorError);
2172
2182
  // Always wrap in RequestError when we have context
2173
2183
  if (currentError instanceof RequestError) {
2174
- currentError = new RequestError(`Err Interceptor ${i + 1} failed: ${errorMessage}`, currentError.url, currentError.method, {
2184
+ currentError = new RequestError(`ErrI${i + 1}: ${em}`, currentError.url, currentError.method, {
2175
2185
  status: currentError.status,
2176
2186
  response: currentError.response,
2177
2187
  });
@@ -2348,6 +2358,11 @@ class BaseRequest {
2348
2358
  // It will check for timeout patterns as a safety net (useful for external AbortControllers)
2349
2359
  throw RequestError.networkError(url, method, errorObj);
2350
2360
  }
2361
+ // Status 0 indicates the request failed before receiving a proper HTTP response
2362
+ // (e.g., CORS errors, network failures that don't throw). Treat as network error.
2363
+ if (response.status === 0) {
2364
+ throw RequestError.networkError(url, method, new Error("Failed with status 0 (network error or CORS blocked)"));
2365
+ }
2351
2366
  if (!response.ok) {
2352
2367
  throw RequestError.fromResponse(response, url, method);
2353
2368
  }
@@ -2447,8 +2462,7 @@ class BodyRequest extends BaseRequest {
2447
2462
  JSON.stringify(body);
2448
2463
  }
2449
2464
  catch (error) {
2450
- const errorMessage = error instanceof Error ? error.message : String(error);
2451
- throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url, this.method);
2465
+ throw new RequestError(`Bad JSON: ${error instanceof Error ? error.message : String(error)}`, this.url, this.method);
2452
2466
  }
2453
2467
  }
2454
2468
  else {
@@ -2495,21 +2509,21 @@ class BodyRequest extends BaseRequest {
2495
2509
  */
2496
2510
  withGraphQL(query, variables, options) {
2497
2511
  if (typeof query !== "string" || query.length === 0) {
2498
- throw new RequestError("Invalid query", this.url, this.method);
2512
+ throw new RequestError("Bad query", this.url, this.method);
2499
2513
  }
2500
2514
  const graphQLBody = {
2501
2515
  query: query,
2502
2516
  };
2503
2517
  if (variables !== undefined) {
2504
2518
  if (typeof variables !== "object" || variables === null || Array.isArray(variables)) {
2505
- throw new RequestError("Invalid vars", this.url, this.method);
2519
+ throw new RequestError("Bad vars", this.url, this.method);
2506
2520
  }
2507
2521
  graphQLBody.variables = variables;
2508
2522
  }
2509
2523
  // Store GraphQL options if provided
2510
2524
  if (options !== undefined) {
2511
2525
  if (typeof options !== "object" || options === null || Array.isArray(options)) {
2512
- throw new RequestError("Invalid options", this.url, this.method);
2526
+ throw new RequestError("Bad opts", this.url, this.method);
2513
2527
  }
2514
2528
  // Store only the known GraphQL options properties
2515
2529
  const opts = options;
@@ -2522,8 +2536,7 @@ class BodyRequest extends BaseRequest {
2522
2536
  JSON.stringify(graphQLBody);
2523
2537
  }
2524
2538
  catch (error) {
2525
- const errorMessage = error instanceof Error ? error.message : String(error);
2526
- throw new RequestError(`Invalid JSON: ${errorMessage}`, this.url, this.method);
2539
+ throw new RequestError(`Bad JSON: ${error instanceof Error ? error.message : String(error)}`, this.url, this.method);
2527
2540
  }
2528
2541
  this.body = graphQLBody;
2529
2542
  this.bodyType = BodyType.JSON;
@@ -2637,7 +2650,7 @@ class DeleteRequest extends BaseRequest {
2637
2650
  *
2638
2651
  * @example
2639
2652
  * const request = new PostRequest('/api/users')
2640
- * .withJson({ name: 'John', email: 'john@example.com' });
2653
+ * .withBody({ name: 'John', email: 'john@example.com' });
2641
2654
  * const data = await request.getData();
2642
2655
  */
2643
2656
  class PostRequest extends BodyRequest {
@@ -2652,7 +2665,7 @@ class PostRequest extends BodyRequest {
2652
2665
  *
2653
2666
  * @example
2654
2667
  * const request = new PutRequest('/api/users/123')
2655
- * .withJson({ id: '123', name: 'John', email: 'john@example.com' });
2668
+ * .withBody({ id: '123', name: 'John', email: 'john@example.com' });
2656
2669
  * const data = await request.getData();
2657
2670
  */
2658
2671
  class PutRequest extends BodyRequest {
@@ -2667,7 +2680,7 @@ class PutRequest extends BodyRequest {
2667
2680
  *
2668
2681
  * @example
2669
2682
  * const request = new PatchRequest('/api/users/123')
2670
- * .withJson({ email: 'new.email@example.com' });
2683
+ * .withBody({ email: 'new.email@example.com' });
2671
2684
  * const data = await request.getData();
2672
2685
  */
2673
2686
  class PatchRequest extends BodyRequest {
@@ -2701,7 +2714,7 @@ function get(url) {
2701
2714
  *
2702
2715
  * @example
2703
2716
  * const request = post('/api/users')
2704
- * .withJson({ name: 'John', email: 'john@example.com' });
2717
+ * .withBody({ name: 'John', email: 'john@example.com' });
2705
2718
  * const newUser = await request.getData();
2706
2719
  */
2707
2720
  function post(url) {
@@ -2716,7 +2729,7 @@ function post(url) {
2716
2729
  *
2717
2730
  * @example
2718
2731
  * const request = put('/api/users/123')
2719
- * .withJson({ name: 'John Updated', email: 'john@example.com' });
2732
+ * .withBody({ name: 'John Updated', email: 'john@example.com' });
2720
2733
  * const updatedUser = await request.getData();
2721
2734
  */
2722
2735
  function put(url) {
@@ -2745,7 +2758,7 @@ function del(url) {
2745
2758
  *
2746
2759
  * @example
2747
2760
  * const request = patch('/api/users/123')
2748
- * .withJson({ status: 'active' });
2761
+ * .withBody({ status: 'active' });
2749
2762
  * const patchedUser = await request.getData();
2750
2763
  */
2751
2764
  function patch(url) {
@@ -2783,267 +2796,155 @@ function options(url) {
2783
2796
  }
2784
2797
 
2785
2798
  /**
2786
- * Resolves a URL against a base URL.
2787
- * If the URL is absolute (starts with http:// or https://), it is returned as-is.
2788
- * Otherwise, it is resolved relative to the base URL.
2789
- *
2790
- * @param baseURL - The base URL to resolve against, or undefined if not set
2791
- * @param url - The URL to resolve, or undefined to return the base URL
2792
- * @returns The resolved absolute URL string
2793
- * @example
2794
- * resolveURL("https://api.example.com", "/users") // "https://api.example.com/users"
2795
- * resolveURL("https://api.example.com", "users") // "https://api.example.com/users"
2796
- * resolveURL("https://api.example.com", "https://other.com") // "https://other.com"
2797
- */
2798
- function resolveURL(baseURL, url) {
2799
- if (!url)
2800
- return baseURL || "";
2801
- if (!baseURL)
2802
- return url;
2803
- if (/^https?:\/\//.test(url))
2804
- return url;
2805
- try {
2806
- return new URL(url, baseURL.endsWith("/") ? baseURL : baseURL + "/").toString();
2807
- }
2808
- catch {
2809
- return baseURL.replace(/\/$/, "") + (url.startsWith("/") ? url : "/" + url);
2810
- }
2811
- }
2812
- /**
2813
- * API builder for creating configured API instances with default settings.
2814
- * Allows you to set default headers, timeouts, authentication, and other options
2815
- * that will be applied to all requests created through this builder.
2816
- *
2817
- * @example
2818
- * ```typescript
2819
- * const api = create.api()
2820
- * .withBaseURL("https://api.example.com")
2821
- * .withBearerToken("token123")
2822
- * .withTimeout(5000);
2823
- *
2824
- * // All requests will use the base URL, bearer token, and timeout
2825
- * await api.get("/users").getJson();
2826
- * await api.post("/posts").withBody({ title: "Hello" }).getJson();
2827
- * ```
2799
+ * Internal API builder implementation.
2828
2800
  */
2829
- class ApiBuilder {
2801
+ class ApiBuilderImpl {
2830
2802
  baseURL;
2831
- modifiers;
2832
- /**
2833
- * Sets the base URL for all requests created through this API builder.
2834
- * Relative URLs will be resolved against this base URL.
2835
- *
2836
- * @param baseURL - The base URL to use for all requests
2837
- * @returns The API builder instance for method chaining
2838
- * @example
2839
- * ```typescript
2840
- * const api = create.api().withBaseURL("https://api.example.com");
2841
- * await api.get("/users").getJson(); // Requests https://api.example.com/users
2842
- * ```
2843
- */
2803
+ modifiers = [];
2804
+ proxy;
2844
2805
  withBaseURL(baseURL) {
2845
2806
  this.baseURL = baseURL;
2846
- return this;
2807
+ return this.getProxy();
2847
2808
  }
2848
- /**
2849
- * Adds a modifier function that will be applied to all requests created through this builder.
2850
- *
2851
- * @private
2852
- * @param modifier - A function that modifies a request and returns it
2853
- * @returns The API builder instance for method chaining
2854
- */
2855
- addModifier(modifier) {
2856
- if (!this.modifiers)
2857
- this.modifiers = [];
2858
- this.modifiers.push(modifier);
2859
- return this;
2809
+ resolveURL(url) {
2810
+ if (!url)
2811
+ return this.baseURL || "";
2812
+ if (/^https?:\/\//.test(url))
2813
+ return url;
2814
+ if (!this.baseURL)
2815
+ return url;
2816
+ return this.baseURL.replace(/\/$/, "") + (url[0] === "/" ? url : "/" + url);
2860
2817
  }
2861
- /**
2862
- * Creates a GET request with the configured default settings.
2863
- *
2864
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2865
- * @returns A GetRequest instance ready to be executed
2866
- * @example
2867
- * ```typescript
2868
- * const api = create.api().withBaseURL("https://api.example.com");
2869
- * await api.get("/users").getJson();
2870
- * await api.get("https://other.com/data").getJson(); // Absolute URL overrides base
2871
- * ```
2872
- */
2873
- get = (url) => {
2874
- const request = get(resolveURL(this.baseURL, url));
2818
+ applyModifiers(request) {
2875
2819
  if (this.modifiers)
2876
2820
  for (const modifier of this.modifiers)
2877
2821
  modifier(request);
2822
+ }
2823
+ get(url) {
2824
+ const request = new GetRequest(this.resolveURL(url));
2825
+ this.applyModifiers(request);
2878
2826
  return request;
2879
- };
2880
- /**
2881
- * Creates a POST request with the configured default settings.
2882
- *
2883
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2884
- * @returns A PostRequest instance ready to be executed
2885
- * @example
2886
- * ```typescript
2887
- * const api = create.api().withBaseURL("https://api.example.com");
2888
- * await api.post("/users").withBody({ name: "John" }).getJson();
2889
- * ```
2890
- */
2891
- post = (url) => {
2892
- const request = post(resolveURL(this.baseURL, url));
2893
- if (this.modifiers)
2894
- for (const modifier of this.modifiers)
2895
- modifier(request);
2827
+ }
2828
+ post(url) {
2829
+ const request = new PostRequest(this.resolveURL(url));
2830
+ this.applyModifiers(request);
2896
2831
  return request;
2897
- };
2898
- /**
2899
- * Creates a PUT request with the configured default settings.
2900
- *
2901
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2902
- * @returns A PutRequest instance ready to be executed
2903
- * @example
2904
- * ```typescript
2905
- * const api = create.api().withBaseURL("https://api.example.com");
2906
- * await api.put("/users/123").withBody({ name: "Jane" }).getJson();
2907
- * ```
2908
- */
2909
- put = (url) => {
2910
- const request = put(resolveURL(this.baseURL, url));
2911
- if (this.modifiers)
2912
- for (const modifier of this.modifiers)
2913
- modifier(request);
2832
+ }
2833
+ put(url) {
2834
+ const request = new PutRequest(this.resolveURL(url));
2835
+ this.applyModifiers(request);
2914
2836
  return request;
2915
- };
2916
- /**
2917
- * Creates a DELETE request with the configured default settings.
2918
- *
2919
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2920
- * @returns A DeleteRequest instance ready to be executed
2921
- * @example
2922
- * ```typescript
2923
- * const api = create.api().withBaseURL("https://api.example.com");
2924
- * await api.del("/users/123").getResponse();
2925
- * ```
2926
- */
2927
- del = (url) => {
2928
- const request = del(resolveURL(this.baseURL, url));
2929
- if (this.modifiers)
2930
- for (const modifier of this.modifiers)
2931
- modifier(request);
2837
+ }
2838
+ del(url) {
2839
+ const request = new DeleteRequest(this.resolveURL(url));
2840
+ this.applyModifiers(request);
2932
2841
  return request;
2933
- };
2934
- /**
2935
- * Creates a PATCH request with the configured default settings.
2936
- *
2937
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2938
- * @returns A PatchRequest instance ready to be executed
2939
- * @example
2940
- * ```typescript
2941
- * const api = create.api().withBaseURL("https://api.example.com");
2942
- * await api.patch("/users/123").withBody({ name: "Updated" }).getJson();
2943
- * ```
2944
- */
2945
- patch = (url) => {
2946
- const request = patch(resolveURL(this.baseURL, url));
2947
- if (this.modifiers)
2948
- for (const modifier of this.modifiers)
2949
- modifier(request);
2842
+ }
2843
+ patch(url) {
2844
+ const request = new PatchRequest(this.resolveURL(url));
2845
+ this.applyModifiers(request);
2950
2846
  return request;
2951
- };
2952
- /**
2953
- * Creates a HEAD request with the configured default settings.
2954
- *
2955
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2956
- * @returns A HeadRequest instance ready to be executed
2957
- * @example
2958
- * ```typescript
2959
- * const api = create.api().withBaseURL("https://api.example.com");
2960
- * const response = await api.head("/users").getResponse();
2961
- * ```
2962
- */
2963
- head = (url) => {
2964
- const request = head(resolveURL(this.baseURL, url));
2965
- if (this.modifiers)
2966
- for (const modifier of this.modifiers)
2967
- modifier(request);
2847
+ }
2848
+ head(url) {
2849
+ const request = new HeadRequest(this.resolveURL(url));
2850
+ this.applyModifiers(request);
2968
2851
  return request;
2969
- };
2970
- /**
2971
- * Creates an OPTIONS request with the configured default settings.
2972
- *
2973
- * @param url - Optional URL path. If not provided, uses the base URL. If relative, resolves against base URL.
2974
- * @returns An OptionsRequest instance ready to be executed
2975
- * @example
2976
- * ```typescript
2977
- * const api = create.api().withBaseURL("https://api.example.com");
2978
- * await api.options("/users").getResponse();
2979
- * ```
2980
- */
2981
- options = (url) => {
2982
- const request = options(resolveURL(this.baseURL, url));
2983
- if (this.modifiers)
2984
- for (const modifier of this.modifiers)
2985
- modifier(request);
2852
+ }
2853
+ options(url) {
2854
+ const request = new OptionsRequest(this.resolveURL(url));
2855
+ this.applyModifiers(request);
2986
2856
  return request;
2987
- };
2988
- /**
2989
- * Creates a new ApiBuilder instance with a Proxy that enables dynamic method forwarding.
2990
- * The Proxy allows calling any `with*` method from BaseRequest on the API builder,
2991
- * which will apply that configuration to all requests created through this builder.
2992
- *
2993
- * @internal
2994
- */
2995
- constructor() {
2996
- const proxy = new Proxy(this, {
2857
+ }
2858
+ addModifier(modifier) {
2859
+ this.modifiers.push(modifier);
2860
+ return this.getProxy();
2861
+ }
2862
+ getProxy() {
2863
+ if (!this.proxy) {
2864
+ this.proxy = this.createProxy();
2865
+ }
2866
+ return this.proxy;
2867
+ }
2868
+ createProxy() {
2869
+ const disallowedMethods = new Set(["withBody", "withGraphQL", "withAbortController"]);
2870
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return
2871
+ return new Proxy(this, {
2997
2872
  get(target, prop) {
2998
- const propertyValue = target[prop];
2999
- if (propertyValue !== undefined) {
3000
- if (typeof propertyValue === "function") {
3001
- return (...args) => {
3002
- const result = propertyValue.apply(target, args);
3003
- return result === target ? proxy : result;
3004
- };
3005
- }
3006
- return propertyValue;
2873
+ const implTarget = target;
2874
+ // Return undefined for disallowed methods
2875
+ if (typeof prop === "string" && disallowedMethods.has(prop)) {
2876
+ return undefined;
3007
2877
  }
3008
- if (typeof prop === "string" && prop.startsWith("with") && prop !== "withBaseURL") {
3009
- if (prop === "withAbortController" || prop === "withBody" || prop === "withGraphQL" || prop === "withQueryParam" || prop === "withQueryParams")
3010
- return undefined;
3011
- const prototypeMethod = BaseRequest.prototype[prop];
3012
- if (typeof prototypeMethod === "function") {
3013
- return (...args) => {
3014
- target.addModifier((request) => prototypeMethod.apply(request, args));
3015
- return proxy;
3016
- };
3017
- }
2878
+ // Check if it's an HTTP method - these should be called directly
2879
+ if (prop === "get" || prop === "post" || prop === "put" || prop === "del" || prop === "patch" || prop === "head" || prop === "options") {
2880
+ return implTarget[prop].bind(implTarget);
2881
+ }
2882
+ // Check if it's a configuration method that already exists
2883
+ if (prop === "withBaseURL") {
2884
+ return implTarget[prop].bind(implTarget);
3018
2885
  }
3019
- return undefined;
2886
+ // Check if the property exists on BaseRequest prototype
2887
+ // If it's a 'with...' method or other chainable method, create a modifier for it
2888
+ if (typeof prop === "string" && (prop.startsWith("with") || prop === "onRetry")) {
2889
+ return (...args) => {
2890
+ return implTarget.addModifier((request) => {
2891
+ const method = request[prop];
2892
+ if (typeof method === "function") {
2893
+ method.apply(request, args);
2894
+ }
2895
+ });
2896
+ };
2897
+ }
2898
+ // For other properties, return them directly if they exist
2899
+ const targetValue = implTarget[prop];
2900
+ return targetValue;
3020
2901
  },
3021
2902
  });
3022
- return proxy;
2903
+ }
2904
+ static create() {
2905
+ return new ApiBuilderImpl().getProxy();
3023
2906
  }
3024
2907
  }
3025
2908
  /**
3026
- * Creates a new API builder instance for configuring default request settings.
3027
- * The builder allows you to set base URLs, authentication, headers, timeouts,
3028
- * and other options that will be applied to all requests created through it.
2909
+ * Creates a new API builder for configuring default request settings.
2910
+ * The API builder allows you to set up a base URL, default headers, timeout,
2911
+ * and other configuration options that will be applied to all requests made through it.
2912
+ *
2913
+ * @returns A new API builder instance
3029
2914
  *
3030
- * @returns A new ApiBuilder instance with all configuration methods available
3031
2915
  * @example
3032
2916
  * ```typescript
3033
- * // Create an API instance with default configuration
3034
- * const api = create.api()
3035
- * .withBaseURL("https://api.example.com")
3036
- * .withBearerToken("your-token")
3037
- * .withTimeout(5000)
3038
- * .withHeaders({ "X-Custom": "value" });
2917
+ * // Create an API instance with defaults
2918
+ * const api = api()
2919
+ * .withBaseURL('https://api.example.com')
2920
+ * .withBearerToken('token123')
2921
+ * .withTimeout(5000);
3039
2922
  *
3040
2923
  * // All requests will use these defaults
3041
- * const users = await api.get("/users").getJson();
3042
- * const newUser = await api.post("/users").withBody({ name: "John" }).getJson();
2924
+ * const users = await api.get('/users').getJson();
2925
+ * const newUser = await api.post('/users').withBody({ name: 'John' }).getJson();
2926
+ * ```
2927
+ *
2928
+ * @example
2929
+ * ```typescript
2930
+ * // Use without URL when baseURL is set
2931
+ * const api = api().withBaseURL('https://api.example.com');
2932
+ * const data = await api.get().getJson(); // Requests to https://api.example.com
2933
+ * ```
2934
+ *
2935
+ * @example
2936
+ * ```typescript
2937
+ * // Override defaults per request
2938
+ * const api = api()
2939
+ * .withBaseURL('https://api.example.com')
2940
+ * .withTimeout(5000);
2941
+ *
2942
+ * // This request uses a longer timeout
2943
+ * await api.get('/slow-endpoint').withTimeout(30000).getJson();
3043
2944
  * ```
3044
2945
  */
3045
2946
  function api() {
3046
- return new ApiBuilder();
2947
+ return ApiBuilderImpl.create();
3047
2948
  }
3048
2949
 
3049
2950
  /**
@@ -3059,7 +2960,7 @@ function api() {
3059
2960
  *
3060
2961
  * // POST request with body
3061
2962
  * const newUser = await create.post('/api/users')
3062
- * .withJson({ name: 'John', email: 'john@example.com' })
2963
+ * .withBody({ name: 'John', email: 'john@example.com' })
3063
2964
  * .getJson();
3064
2965
  *
3065
2966
  * // Configure API instance with defaults
@@ -3082,5 +2983,5 @@ const create = {
3082
2983
  config: Config.getInstance(),
3083
2984
  };
3084
2985
 
3085
- export { CacheMode, CookieUtils, CredentialsPolicy, DeleteRequest, GetRequest, HeadRequest, HttpMethod, OptionsRequest, PatchRequest, PostRequest, PutRequest, RedirectMode, ReferrerPolicy, RequestError, RequestMode, RequestPriority, ResponseWrapper, SameSitePolicy, api, create as default, del, get, head, options, patch, post, put };
2986
+ export { CacheMode, CookieUtils, CredentialsPolicy, DeleteRequest, GetRequest, HeadRequest, HttpMethod, OptionsRequest, PatchRequest, PostRequest, PutRequest, RedirectMode, ReferrerPolicy, RequestError, RequestMode, RequestPriority, ResponseWrapper, SameSitePolicy, api as createApi, del as createDelete, get as createGet, head as createHead, options as createOptions, patch as createPatch, post as createPost, put as createPut, create as default };
3086
2987
  //# sourceMappingURL=index.esm.js.map