create-request 1.4.3-rc.4 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -12
- package/dist/library/BaseRequest.d.ts +20 -5
- package/dist/library/RequestError.d.ts +2 -2
- package/dist/library/apiBuilder.d.ts +476 -115
- package/dist/library/index.cjs +192 -291
- package/dist/library/index.cjs.map +1 -1
- package/dist/library/index.d.ts +3 -3
- package/dist/library/index.esm.js +184 -283
- package/dist/library/index.esm.js.map +1 -1
- package/dist/library/index.esm.min.js +1 -1
- package/dist/library/index.esm.min.js.map +1 -1
- package/dist/library/index.min.cjs +1 -1
- package/dist/library/index.min.cjs.map +1 -1
- package/dist/library/requestFactories.d.ts +3 -3
- package/dist/library/requestMethods.d.ts +3 -3
- package/dist/library/types.d.ts +8 -8
- package/package.json +38 -36
|
@@ -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
|
|
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
|
|
249
|
+
message = `Timeout:${url}`;
|
|
250
250
|
}
|
|
251
251
|
else if (isDnsError) {
|
|
252
|
-
message = `DNS
|
|
252
|
+
message = `DNS:${url}`;
|
|
253
253
|
}
|
|
254
254
|
else if (isConnectionError) {
|
|
255
|
-
message = `
|
|
255
|
+
message = `Conn:${url}`;
|
|
256
256
|
}
|
|
257
257
|
else {
|
|
258
|
-
message = `
|
|
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
|
|
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(`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1056
|
+
throw new RequestError(errorMessage, url, this.method);
|
|
1061
1057
|
if (url.includes("\0") || url.includes("\r") || url.includes("\n")) {
|
|
1062
|
-
throw new RequestError(
|
|
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(
|
|
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("
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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("
|
|
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(`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(`
|
|
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
|
-
|
|
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("
|
|
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("
|
|
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("
|
|
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
|
-
|
|
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
|
-
* .
|
|
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
|
-
* .
|
|
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
|
-
* .
|
|
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
|
-
* .
|
|
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
|
-
* .
|
|
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
|
-
* .
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
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-unsafe-return
|
|
2871
|
+
return new Proxy(this, {
|
|
2997
2872
|
get(target, prop) {
|
|
2998
|
-
const
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
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
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2903
|
+
}
|
|
2904
|
+
static create() {
|
|
2905
|
+
return new ApiBuilderImpl().getProxy();
|
|
3023
2906
|
}
|
|
3024
2907
|
}
|
|
3025
2908
|
/**
|
|
3026
|
-
* Creates a new API builder
|
|
3027
|
-
* The builder allows you to set base
|
|
3028
|
-
* and other options that will be applied to all requests
|
|
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
|
|
3034
|
-
* const api =
|
|
3035
|
-
* .withBaseURL(
|
|
3036
|
-
* .withBearerToken(
|
|
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(
|
|
3042
|
-
* const newUser = await api.post(
|
|
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
|
|
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
|
-
* .
|
|
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
|
|
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
|