@fgrzl/fetch 1.4.0-alpha.2 → 1.4.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.
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ var FetchClient = class {
4
4
  this.middlewares = [];
5
5
  this.credentials = config.credentials ?? "same-origin";
6
6
  this.baseUrl = config.baseUrl;
7
+ this.defaultTimeout = config.timeout;
7
8
  }
8
9
  use(middleware) {
9
10
  this.middlewares.push(middleware);
@@ -29,7 +30,7 @@ var FetchClient = class {
29
30
  *
30
31
  * @example Chain with middleware:
31
32
  * ```typescript
32
- * const client = useProductionStack(new FetchClient())
33
+ * const client = addProductionStack(new FetchClient())
33
34
  * .setBaseUrl(process.env.API_BASE_URL);
34
35
  * ```
35
36
  */
@@ -37,11 +38,31 @@ var FetchClient = class {
37
38
  this.baseUrl = baseUrl;
38
39
  return this;
39
40
  }
40
- async request(url, init = {}) {
41
+ async request(url, init = {}, options) {
41
42
  const resolvedUrl = this.resolveUrl(url);
43
+ let timeoutId;
44
+ let timeoutController;
45
+ let effectiveSignal = options?.signal || init.signal;
46
+ const timeoutMs = options?.timeout ?? this.defaultTimeout;
47
+ if (timeoutMs && timeoutMs > 0) {
48
+ timeoutController = new AbortController();
49
+ if (effectiveSignal) {
50
+ effectiveSignal.addEventListener("abort", () => {
51
+ timeoutController?.abort();
52
+ });
53
+ }
54
+ effectiveSignal = timeoutController.signal;
55
+ timeoutId = setTimeout(() => {
56
+ timeoutController?.abort();
57
+ }, timeoutMs);
58
+ }
42
59
  let index = 0;
43
60
  const execute = async (request) => {
44
- const currentRequest = request || { ...init, url: resolvedUrl };
61
+ const currentRequest = request || {
62
+ ...init,
63
+ url: resolvedUrl,
64
+ ...effectiveSignal ? { signal: effectiveSignal } : {}
65
+ };
45
66
  const currentUrl = currentRequest.url || resolvedUrl;
46
67
  if (index >= this.middlewares.length) {
47
68
  const { url: _, ...requestInit } = currentRequest;
@@ -54,8 +75,14 @@ var FetchClient = class {
54
75
  }
55
76
  return middleware(currentRequest, execute);
56
77
  };
57
- const result = await execute();
58
- return result;
78
+ try {
79
+ const result = await execute();
80
+ return result;
81
+ } finally {
82
+ if (timeoutId !== void 0) {
83
+ clearTimeout(timeoutId);
84
+ }
85
+ }
59
86
  }
60
87
  async coreFetch(request, url) {
61
88
  try {
@@ -87,6 +114,20 @@ var FetchClient = class {
87
114
  }
88
115
  };
89
116
  } catch (error) {
117
+ if (error instanceof Error && error.name === "AbortError") {
118
+ return {
119
+ data: null,
120
+ status: 0,
121
+ statusText: "Request Aborted",
122
+ headers: new Headers(),
123
+ url,
124
+ ok: false,
125
+ error: {
126
+ message: "Request was aborted",
127
+ body: error
128
+ }
129
+ };
130
+ }
90
131
  if (error instanceof TypeError && error.message.includes("fetch")) {
91
132
  return {
92
133
  data: null,
@@ -179,6 +220,7 @@ var FetchClient = class {
179
220
  * @template T - Expected response data type (will be null for HEAD requests)
180
221
  * @param url - Request URL
181
222
  * @param params - Query parameters to append to URL
223
+ * @param options - Request options (signal, timeout)
182
224
  * @returns Promise resolving to typed response (data will always be null)
183
225
  *
184
226
  * @example Check if resource exists:
@@ -191,17 +233,16 @@ var FetchClient = class {
191
233
  * }
192
234
  * ```
193
235
  *
194
- * @example Check with query parameters:
236
+ * @example With cancellation:
195
237
  * ```typescript
196
- * const exists = await client.head('/api/users', { id: 123 });
197
- * if (exists.status === 404) {
198
- * console.log('User not found');
199
- * }
238
+ * const controller = new AbortController();
239
+ * const request = client.head('/api/users', { id: 123 }, { signal: controller.signal });
240
+ * controller.abort(); // Cancel the request
200
241
  * ```
201
242
  */
202
- head(url, params) {
243
+ head(url, params, options) {
203
244
  const finalUrl = this.buildUrlWithParams(url, params);
204
- return this.request(finalUrl, { method: "HEAD" });
245
+ return this.request(finalUrl, { method: "HEAD" }, options);
205
246
  }
206
247
  /**
207
248
  * HEAD request that returns useful metadata about a resource.
@@ -244,6 +285,7 @@ var FetchClient = class {
244
285
  * @template T - Expected response data type
245
286
  * @param url - Request URL
246
287
  * @param params - Query parameters to append to URL
288
+ * @param options - Request options (signal, timeout)
247
289
  * @returns Promise resolving to typed response
248
290
  *
249
291
  * @example
@@ -252,10 +294,15 @@ var FetchClient = class {
252
294
  * const filteredUsers = await client.get<User[]>('/api/users', { status: 'active', limit: 10 });
253
295
  * if (users.ok) console.log(users.data);
254
296
  * ```
297
+ *
298
+ * @example With timeout:
299
+ * ```typescript
300
+ * const users = await client.get<User[]>('/api/users', {}, { timeout: 5000 });
301
+ * ```
255
302
  */
256
- get(url, params) {
303
+ get(url, params, options) {
257
304
  const finalUrl = this.buildUrlWithParams(url, params);
258
- return this.request(finalUrl, { method: "GET" });
305
+ return this.request(finalUrl, { method: "GET" }, options);
259
306
  }
260
307
  /**
261
308
  * POST request with automatic JSON serialization.
@@ -264,23 +311,35 @@ var FetchClient = class {
264
311
  * @param url - Request URL
265
312
  * @param body - Request body (auto-serialized to JSON)
266
313
  * @param headers - Additional headers (Content-Type: application/json is default)
314
+ * @param options - Request options (signal, timeout)
267
315
  * @returns Promise resolving to typed response
268
316
  *
269
317
  * @example
270
318
  * ```typescript
271
319
  * const result = await client.post<User>('/api/users', { name: 'John' });
272
320
  * ```
321
+ *
322
+ * @example With cancellation:
323
+ * ```typescript
324
+ * const controller = new AbortController();
325
+ * const result = client.post('/api/users', { name: 'John' }, {}, { signal: controller.signal });
326
+ * controller.abort();
327
+ * ```
273
328
  */
274
- post(url, body, headers) {
329
+ post(url, body, headers, options) {
275
330
  const requestHeaders = {
276
331
  "Content-Type": "application/json",
277
332
  ...headers ?? {}
278
333
  };
279
- return this.request(url, {
280
- method: "POST",
281
- headers: requestHeaders,
282
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
283
- });
334
+ return this.request(
335
+ url,
336
+ {
337
+ method: "POST",
338
+ headers: requestHeaders,
339
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
340
+ },
341
+ options
342
+ );
284
343
  }
285
344
  /**
286
345
  * PUT request with automatic JSON serialization.
@@ -289,18 +348,23 @@ var FetchClient = class {
289
348
  * @param url - Request URL
290
349
  * @param body - Request body (auto-serialized to JSON)
291
350
  * @param headers - Additional headers (Content-Type: application/json is default)
351
+ * @param options - Request options (signal, timeout)
292
352
  * @returns Promise resolving to typed response
293
353
  */
294
- put(url, body, headers) {
354
+ put(url, body, headers, options) {
295
355
  const requestHeaders = {
296
356
  "Content-Type": "application/json",
297
357
  ...headers ?? {}
298
358
  };
299
- return this.request(url, {
300
- method: "PUT",
301
- headers: requestHeaders,
302
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
303
- });
359
+ return this.request(
360
+ url,
361
+ {
362
+ method: "PUT",
363
+ headers: requestHeaders,
364
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
365
+ },
366
+ options
367
+ );
304
368
  }
305
369
  /**
306
370
  * PATCH request with automatic JSON serialization.
@@ -309,18 +373,23 @@ var FetchClient = class {
309
373
  * @param url - Request URL
310
374
  * @param body - Request body (auto-serialized to JSON)
311
375
  * @param headers - Additional headers (Content-Type: application/json is default)
376
+ * @param options - Request options (signal, timeout)
312
377
  * @returns Promise resolving to typed response
313
378
  */
314
- patch(url, body, headers) {
379
+ patch(url, body, headers, options) {
315
380
  const requestHeaders = {
316
381
  "Content-Type": "application/json",
317
382
  ...headers ?? {}
318
383
  };
319
- return this.request(url, {
320
- method: "PATCH",
321
- headers: requestHeaders,
322
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
323
- });
384
+ return this.request(
385
+ url,
386
+ {
387
+ method: "PATCH",
388
+ headers: requestHeaders,
389
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
390
+ },
391
+ options
392
+ );
324
393
  }
325
394
  /**
326
395
  * DELETE request with query parameter support.
@@ -328,6 +397,7 @@ var FetchClient = class {
328
397
  * @template T - Expected response data type
329
398
  * @param url - Request URL
330
399
  * @param params - Query parameters to append to URL
400
+ * @param options - Request options (signal, timeout)
331
401
  * @returns Promise resolving to typed response
332
402
  *
333
403
  * @example
@@ -337,9 +407,9 @@ var FetchClient = class {
337
407
  * if (result.ok) console.log('Deleted successfully');
338
408
  * ```
339
409
  */
340
- del(url, params) {
410
+ del(url, params, options) {
341
411
  const finalUrl = this.buildUrlWithParams(url, params);
342
- return this.request(finalUrl, { method: "DELETE" });
412
+ return this.request(finalUrl, { method: "DELETE" }, options);
343
413
  }
344
414
  };
345
415
 
@@ -397,7 +467,7 @@ function createAuthenticationMiddleware(options) {
397
467
  }
398
468
 
399
469
  // src/middleware/authentication/index.ts
400
- function useAuthentication(client, options) {
470
+ function addAuthentication(client, options) {
401
471
  return client.use(createAuthenticationMiddleware(options));
402
472
  }
403
473
 
@@ -476,7 +546,7 @@ function createAuthorizationMiddleware(options = {}) {
476
546
  }
477
547
 
478
548
  // src/middleware/authorization/index.ts
479
- function useAuthorization(client, options = {}) {
549
+ function addAuthorization(client, options = {}) {
480
550
  return client.use(createAuthorizationMiddleware(options));
481
551
  }
482
552
 
@@ -620,7 +690,7 @@ function createCacheMiddleware(options = {}) {
620
690
  }
621
691
 
622
692
  // src/middleware/cache/index.ts
623
- function useCache(client, options = {}) {
693
+ function addCache(client, options = {}) {
624
694
  return client.use(createCacheMiddleware(options));
625
695
  }
626
696
 
@@ -677,7 +747,7 @@ function createCSRFMiddleware(options = {}) {
677
747
  }
678
748
 
679
749
  // src/middleware/csrf/index.ts
680
- function useCSRF(client, options = {}) {
750
+ function addCSRF(client, options = {}) {
681
751
  return client.use(createCSRFMiddleware(options));
682
752
  }
683
753
 
@@ -809,7 +879,7 @@ function getHeadersObject(headers) {
809
879
  }
810
880
 
811
881
  // src/middleware/logging/index.ts
812
- function useLogging(client, options = {}) {
882
+ function addLogging(client, options = {}) {
813
883
  return client.use(createLoggingMiddleware(options));
814
884
  }
815
885
 
@@ -892,7 +962,7 @@ function createRateLimitMiddleware(options = {}) {
892
962
  }
893
963
 
894
964
  // src/middleware/rate-limit/index.ts
895
- function useRateLimit(client, options = {}) {
965
+ function addRateLimit(client, options = {}) {
896
966
  return client.use(createRateLimitMiddleware(options));
897
967
  }
898
968
 
@@ -990,40 +1060,40 @@ function createRetryMiddleware(options = {}) {
990
1060
  }
991
1061
 
992
1062
  // src/middleware/retry/index.ts
993
- function useRetry(client, options = {}) {
1063
+ function addRetry(client, options = {}) {
994
1064
  return client.use(createRetryMiddleware(options));
995
1065
  }
996
1066
 
997
1067
  // src/middleware/index.ts
998
- function useProductionStack(client, config = {}) {
1068
+ function addProductionStack(client, config = {}) {
999
1069
  let enhanced = client;
1000
1070
  if (config.auth) {
1001
- enhanced = useAuthentication(enhanced, config.auth);
1071
+ enhanced = addAuthentication(enhanced, config.auth);
1002
1072
  }
1003
1073
  if (config.cache !== void 0) {
1004
- enhanced = useCache(enhanced, config.cache);
1074
+ enhanced = addCache(enhanced, config.cache);
1005
1075
  }
1006
1076
  if (config.retry !== void 0) {
1007
- enhanced = useRetry(enhanced, config.retry);
1077
+ enhanced = addRetry(enhanced, config.retry);
1008
1078
  }
1009
1079
  if (config.rateLimit !== void 0) {
1010
- enhanced = useRateLimit(enhanced, config.rateLimit);
1080
+ enhanced = addRateLimit(enhanced, config.rateLimit);
1011
1081
  }
1012
1082
  if (config.logging !== void 0) {
1013
- enhanced = useLogging(enhanced, config.logging);
1083
+ enhanced = addLogging(enhanced, config.logging);
1014
1084
  }
1015
1085
  return enhanced;
1016
1086
  }
1017
- function useDevelopmentStack(client, config = {}) {
1087
+ function addDevelopmentStack(client, config = {}) {
1018
1088
  let enhanced = client;
1019
1089
  if (config.auth) {
1020
- enhanced = useAuthentication(enhanced, config.auth);
1090
+ enhanced = addAuthentication(enhanced, config.auth);
1021
1091
  }
1022
- enhanced = useRetry(enhanced, {
1092
+ enhanced = addRetry(enhanced, {
1023
1093
  maxRetries: 1,
1024
1094
  delay: 100
1025
1095
  });
1026
- enhanced = useLogging(enhanced, {
1096
+ enhanced = addLogging(enhanced, {
1027
1097
  level: "debug",
1028
1098
  includeRequestHeaders: true,
1029
1099
  includeResponseHeaders: true,
@@ -1032,8 +1102,8 @@ function useDevelopmentStack(client, config = {}) {
1032
1102
  });
1033
1103
  return enhanced;
1034
1104
  }
1035
- function useBasicStack(client, config) {
1036
- return useRetry(useAuthentication(client, config.auth), { maxRetries: 2 });
1105
+ function addBasicStack(client, config) {
1106
+ return addRetry(addAuthentication(client, config.auth), { maxRetries: 2 });
1037
1107
  }
1038
1108
 
1039
1109
  // src/errors/index.ts
@@ -1115,7 +1185,7 @@ function appendQueryParams(baseUrl, query) {
1115
1185
  }
1116
1186
 
1117
1187
  // src/index.ts
1118
- var api = useProductionStack(
1188
+ var api = addProductionStack(
1119
1189
  new FetchClient({
1120
1190
  // Smart default: include cookies for session-based auth
1121
1191
  // Can be overridden by creating a custom FetchClient
@@ -1143,29 +1213,7 @@ var api = useProductionStack(
1143
1213
  }
1144
1214
  );
1145
1215
  var index_default = api;
1146
- export {
1147
- FetchClient,
1148
- FetchError,
1149
- HttpError,
1150
- NetworkError,
1151
- appendQueryParams,
1152
- buildQueryParams,
1153
- createAuthenticationMiddleware,
1154
- createAuthorizationMiddleware,
1155
- createCacheMiddleware,
1156
- createLoggingMiddleware,
1157
- createRateLimitMiddleware,
1158
- createRetryMiddleware,
1159
- index_default as default,
1160
- useAuthentication,
1161
- useAuthorization,
1162
- useBasicStack,
1163
- useCSRF,
1164
- useCache,
1165
- useDevelopmentStack,
1166
- useLogging,
1167
- useProductionStack,
1168
- useRateLimit,
1169
- useRetry
1170
- };
1216
+
1217
+ export { FetchClient, FetchError, HttpError, NetworkError, addAuthentication, addAuthorization, addBasicStack, addCSRF, addCache, addDevelopmentStack, addLogging, addProductionStack, addRateLimit, addRetry, appendQueryParams, buildQueryParams, createAuthenticationMiddleware, createAuthorizationMiddleware, createCacheMiddleware, createLoggingMiddleware, createRateLimitMiddleware, createRetryMiddleware, index_default as default };
1218
+ //# sourceMappingURL=index.js.map
1171
1219
  //# sourceMappingURL=index.js.map