@fgrzl/fetch 1.1.0-alpha.7 → 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.
Files changed (224) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/CONTRIBUTING.md +327 -0
  3. package/README.md +50 -21
  4. package/dist/cjs/index.js +1110 -105
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/index.min.js +2 -0
  7. package/dist/cjs/index.min.js.map +1 -0
  8. package/dist/index.d.ts +1381 -10
  9. package/dist/index.js +1066 -91
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.min.js +2 -0
  12. package/dist/index.min.js.map +1 -0
  13. package/package.json +14 -5
  14. package/dist/cjs/client/fetch-client.d.ts +0 -189
  15. package/dist/cjs/client/fetch-client.d.ts.map +0 -1
  16. package/dist/cjs/client/fetch-client.js +0 -339
  17. package/dist/cjs/client/fetch-client.js.map +0 -1
  18. package/dist/cjs/client/index.d.ts +0 -11
  19. package/dist/cjs/client/index.d.ts.map +0 -1
  20. package/dist/cjs/client/index.js +0 -14
  21. package/dist/cjs/client/index.js.map +0 -1
  22. package/dist/cjs/client/types.d.ts +0 -63
  23. package/dist/cjs/client/types.d.ts.map +0 -1
  24. package/dist/cjs/client/types.js +0 -9
  25. package/dist/cjs/client/types.js.map +0 -1
  26. package/dist/cjs/errors/index.d.ts +0 -64
  27. package/dist/cjs/errors/index.d.ts.map +0 -1
  28. package/dist/cjs/errors/index.js +0 -79
  29. package/dist/cjs/errors/index.js.map +0 -1
  30. package/dist/cjs/index.d.ts +0 -65
  31. package/dist/cjs/index.d.ts.map +0 -1
  32. package/dist/cjs/middleware/authentication/authentication.d.ts +0 -31
  33. package/dist/cjs/middleware/authentication/authentication.d.ts.map +0 -1
  34. package/dist/cjs/middleware/authentication/authentication.js +0 -93
  35. package/dist/cjs/middleware/authentication/authentication.js.map +0 -1
  36. package/dist/cjs/middleware/authentication/index.d.ts +0 -37
  37. package/dist/cjs/middleware/authentication/index.d.ts.map +0 -1
  38. package/dist/cjs/middleware/authentication/index.js +0 -42
  39. package/dist/cjs/middleware/authentication/index.js.map +0 -1
  40. package/dist/cjs/middleware/authentication/types.d.ts +0 -73
  41. package/dist/cjs/middleware/authentication/types.d.ts.map +0 -1
  42. package/dist/cjs/middleware/authentication/types.js +0 -6
  43. package/dist/cjs/middleware/authentication/types.js.map +0 -1
  44. package/dist/cjs/middleware/authorization/authorization.d.ts +0 -30
  45. package/dist/cjs/middleware/authorization/authorization.d.ts.map +0 -1
  46. package/dist/cjs/middleware/authorization/authorization.js +0 -82
  47. package/dist/cjs/middleware/authorization/authorization.js.map +0 -1
  48. package/dist/cjs/middleware/authorization/index.d.ts +0 -36
  49. package/dist/cjs/middleware/authorization/index.d.ts.map +0 -1
  50. package/dist/cjs/middleware/authorization/index.js +0 -41
  51. package/dist/cjs/middleware/authorization/index.js.map +0 -1
  52. package/dist/cjs/middleware/authorization/types.d.ts +0 -67
  53. package/dist/cjs/middleware/authorization/types.d.ts.map +0 -1
  54. package/dist/cjs/middleware/authorization/types.js +0 -6
  55. package/dist/cjs/middleware/authorization/types.js.map +0 -1
  56. package/dist/cjs/middleware/cache/cache.d.ts +0 -41
  57. package/dist/cjs/middleware/cache/cache.d.ts.map +0 -1
  58. package/dist/cjs/middleware/cache/cache.js +0 -191
  59. package/dist/cjs/middleware/cache/cache.js.map +0 -1
  60. package/dist/cjs/middleware/cache/index.d.ts +0 -44
  61. package/dist/cjs/middleware/cache/index.d.ts.map +0 -1
  62. package/dist/cjs/middleware/cache/index.js +0 -50
  63. package/dist/cjs/middleware/cache/index.js.map +0 -1
  64. package/dist/cjs/middleware/cache/types.d.ts +0 -89
  65. package/dist/cjs/middleware/cache/types.d.ts.map +0 -1
  66. package/dist/cjs/middleware/cache/types.js +0 -6
  67. package/dist/cjs/middleware/cache/types.js.map +0 -1
  68. package/dist/cjs/middleware/csrf/csrf.d.ts +0 -34
  69. package/dist/cjs/middleware/csrf/csrf.d.ts.map +0 -1
  70. package/dist/cjs/middleware/csrf/csrf.js +0 -94
  71. package/dist/cjs/middleware/csrf/csrf.js.map +0 -1
  72. package/dist/cjs/middleware/csrf/index.d.ts +0 -57
  73. package/dist/cjs/middleware/csrf/index.d.ts.map +0 -1
  74. package/dist/cjs/middleware/csrf/index.js +0 -62
  75. package/dist/cjs/middleware/csrf/index.js.map +0 -1
  76. package/dist/cjs/middleware/csrf/types.d.ts +0 -57
  77. package/dist/cjs/middleware/csrf/types.d.ts.map +0 -1
  78. package/dist/cjs/middleware/csrf/types.js +0 -6
  79. package/dist/cjs/middleware/csrf/types.js.map +0 -1
  80. package/dist/cjs/middleware/index.d.ts +0 -115
  81. package/dist/cjs/middleware/index.d.ts.map +0 -1
  82. package/dist/cjs/middleware/index.js +0 -153
  83. package/dist/cjs/middleware/index.js.map +0 -1
  84. package/dist/cjs/middleware/logging/index.d.ts +0 -42
  85. package/dist/cjs/middleware/logging/index.d.ts.map +0 -1
  86. package/dist/cjs/middleware/logging/index.js +0 -47
  87. package/dist/cjs/middleware/logging/index.js.map +0 -1
  88. package/dist/cjs/middleware/logging/logging.d.ts +0 -29
  89. package/dist/cjs/middleware/logging/logging.d.ts.map +0 -1
  90. package/dist/cjs/middleware/logging/logging.js +0 -171
  91. package/dist/cjs/middleware/logging/logging.js.map +0 -1
  92. package/dist/cjs/middleware/logging/types.d.ts +0 -90
  93. package/dist/cjs/middleware/logging/types.d.ts.map +0 -1
  94. package/dist/cjs/middleware/logging/types.js +0 -6
  95. package/dist/cjs/middleware/logging/types.js.map +0 -1
  96. package/dist/cjs/middleware/rate-limit/index.d.ts +0 -16
  97. package/dist/cjs/middleware/rate-limit/index.d.ts.map +0 -1
  98. package/dist/cjs/middleware/rate-limit/index.js +0 -21
  99. package/dist/cjs/middleware/rate-limit/index.js.map +0 -1
  100. package/dist/cjs/middleware/rate-limit/rate-limit.d.ts +0 -14
  101. package/dist/cjs/middleware/rate-limit/rate-limit.d.ts.map +0 -1
  102. package/dist/cjs/middleware/rate-limit/rate-limit.js +0 -87
  103. package/dist/cjs/middleware/rate-limit/rate-limit.js.map +0 -1
  104. package/dist/cjs/middleware/rate-limit/types.d.ts +0 -97
  105. package/dist/cjs/middleware/rate-limit/types.d.ts.map +0 -1
  106. package/dist/cjs/middleware/rate-limit/types.js +0 -6
  107. package/dist/cjs/middleware/rate-limit/types.js.map +0 -1
  108. package/dist/cjs/middleware/retry/index.d.ts +0 -6
  109. package/dist/cjs/middleware/retry/index.d.ts.map +0 -1
  110. package/dist/cjs/middleware/retry/index.js +0 -11
  111. package/dist/cjs/middleware/retry/index.js.map +0 -1
  112. package/dist/cjs/middleware/retry/retry.d.ts +0 -39
  113. package/dist/cjs/middleware/retry/retry.d.ts.map +0 -1
  114. package/dist/cjs/middleware/retry/retry.js +0 -144
  115. package/dist/cjs/middleware/retry/retry.js.map +0 -1
  116. package/dist/cjs/middleware/retry/types.d.ts +0 -61
  117. package/dist/cjs/middleware/retry/types.d.ts.map +0 -1
  118. package/dist/cjs/middleware/retry/types.js +0 -6
  119. package/dist/cjs/middleware/retry/types.js.map +0 -1
  120. package/dist/client/fetch-client.d.ts +0 -189
  121. package/dist/client/fetch-client.d.ts.map +0 -1
  122. package/dist/client/fetch-client.js +0 -335
  123. package/dist/client/fetch-client.js.map +0 -1
  124. package/dist/client/index.d.ts +0 -11
  125. package/dist/client/index.d.ts.map +0 -1
  126. package/dist/client/index.js +0 -10
  127. package/dist/client/index.js.map +0 -1
  128. package/dist/client/types.d.ts +0 -63
  129. package/dist/client/types.d.ts.map +0 -1
  130. package/dist/client/types.js +0 -8
  131. package/dist/client/types.js.map +0 -1
  132. package/dist/errors/index.d.ts +0 -64
  133. package/dist/errors/index.d.ts.map +0 -1
  134. package/dist/errors/index.js +0 -73
  135. package/dist/errors/index.js.map +0 -1
  136. package/dist/index.d.ts.map +0 -1
  137. package/dist/middleware/authentication/authentication.d.ts +0 -31
  138. package/dist/middleware/authentication/authentication.d.ts.map +0 -1
  139. package/dist/middleware/authentication/authentication.js +0 -90
  140. package/dist/middleware/authentication/authentication.js.map +0 -1
  141. package/dist/middleware/authentication/index.d.ts +0 -37
  142. package/dist/middleware/authentication/index.d.ts.map +0 -1
  143. package/dist/middleware/authentication/index.js +0 -37
  144. package/dist/middleware/authentication/index.js.map +0 -1
  145. package/dist/middleware/authentication/types.d.ts +0 -73
  146. package/dist/middleware/authentication/types.d.ts.map +0 -1
  147. package/dist/middleware/authentication/types.js +0 -5
  148. package/dist/middleware/authentication/types.js.map +0 -1
  149. package/dist/middleware/authorization/authorization.d.ts +0 -30
  150. package/dist/middleware/authorization/authorization.d.ts.map +0 -1
  151. package/dist/middleware/authorization/authorization.js +0 -79
  152. package/dist/middleware/authorization/authorization.js.map +0 -1
  153. package/dist/middleware/authorization/index.d.ts +0 -36
  154. package/dist/middleware/authorization/index.d.ts.map +0 -1
  155. package/dist/middleware/authorization/index.js +0 -36
  156. package/dist/middleware/authorization/index.js.map +0 -1
  157. package/dist/middleware/authorization/types.d.ts +0 -67
  158. package/dist/middleware/authorization/types.d.ts.map +0 -1
  159. package/dist/middleware/authorization/types.js +0 -5
  160. package/dist/middleware/authorization/types.js.map +0 -1
  161. package/dist/middleware/cache/cache.d.ts +0 -41
  162. package/dist/middleware/cache/cache.d.ts.map +0 -1
  163. package/dist/middleware/cache/cache.js +0 -186
  164. package/dist/middleware/cache/cache.js.map +0 -1
  165. package/dist/middleware/cache/index.d.ts +0 -44
  166. package/dist/middleware/cache/index.d.ts.map +0 -1
  167. package/dist/middleware/cache/index.js +0 -44
  168. package/dist/middleware/cache/index.js.map +0 -1
  169. package/dist/middleware/cache/types.d.ts +0 -89
  170. package/dist/middleware/cache/types.d.ts.map +0 -1
  171. package/dist/middleware/cache/types.js +0 -5
  172. package/dist/middleware/cache/types.js.map +0 -1
  173. package/dist/middleware/csrf/csrf.d.ts +0 -34
  174. package/dist/middleware/csrf/csrf.d.ts.map +0 -1
  175. package/dist/middleware/csrf/csrf.js +0 -91
  176. package/dist/middleware/csrf/csrf.js.map +0 -1
  177. package/dist/middleware/csrf/index.d.ts +0 -57
  178. package/dist/middleware/csrf/index.d.ts.map +0 -1
  179. package/dist/middleware/csrf/index.js +0 -57
  180. package/dist/middleware/csrf/index.js.map +0 -1
  181. package/dist/middleware/csrf/types.d.ts +0 -57
  182. package/dist/middleware/csrf/types.d.ts.map +0 -1
  183. package/dist/middleware/csrf/types.js +0 -5
  184. package/dist/middleware/csrf/types.js.map +0 -1
  185. package/dist/middleware/index.d.ts +0 -115
  186. package/dist/middleware/index.d.ts.map +0 -1
  187. package/dist/middleware/index.js +0 -134
  188. package/dist/middleware/index.js.map +0 -1
  189. package/dist/middleware/logging/index.d.ts +0 -42
  190. package/dist/middleware/logging/index.d.ts.map +0 -1
  191. package/dist/middleware/logging/index.js +0 -42
  192. package/dist/middleware/logging/index.js.map +0 -1
  193. package/dist/middleware/logging/logging.d.ts +0 -29
  194. package/dist/middleware/logging/logging.d.ts.map +0 -1
  195. package/dist/middleware/logging/logging.js +0 -168
  196. package/dist/middleware/logging/logging.js.map +0 -1
  197. package/dist/middleware/logging/types.d.ts +0 -90
  198. package/dist/middleware/logging/types.d.ts.map +0 -1
  199. package/dist/middleware/logging/types.js +0 -5
  200. package/dist/middleware/logging/types.js.map +0 -1
  201. package/dist/middleware/rate-limit/index.d.ts +0 -16
  202. package/dist/middleware/rate-limit/index.d.ts.map +0 -1
  203. package/dist/middleware/rate-limit/index.js +0 -16
  204. package/dist/middleware/rate-limit/index.js.map +0 -1
  205. package/dist/middleware/rate-limit/rate-limit.d.ts +0 -14
  206. package/dist/middleware/rate-limit/rate-limit.d.ts.map +0 -1
  207. package/dist/middleware/rate-limit/rate-limit.js +0 -84
  208. package/dist/middleware/rate-limit/rate-limit.js.map +0 -1
  209. package/dist/middleware/rate-limit/types.d.ts +0 -97
  210. package/dist/middleware/rate-limit/types.d.ts.map +0 -1
  211. package/dist/middleware/rate-limit/types.js +0 -5
  212. package/dist/middleware/rate-limit/types.js.map +0 -1
  213. package/dist/middleware/retry/index.d.ts +0 -6
  214. package/dist/middleware/retry/index.d.ts.map +0 -1
  215. package/dist/middleware/retry/index.js +0 -6
  216. package/dist/middleware/retry/index.js.map +0 -1
  217. package/dist/middleware/retry/retry.d.ts +0 -39
  218. package/dist/middleware/retry/retry.d.ts.map +0 -1
  219. package/dist/middleware/retry/retry.js +0 -141
  220. package/dist/middleware/retry/retry.js.map +0 -1
  221. package/dist/middleware/retry/types.d.ts +0 -61
  222. package/dist/middleware/retry/types.d.ts.map +0 -1
  223. package/dist/middleware/retry/types.js +0 -5
  224. package/dist/middleware/retry/types.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,102 +1,1077 @@
1
- /**
2
- * @fileoverview Main library entry point with "pit of success" architecture.
3
- *
4
- * This module exports everything users need in order of discoverability:
5
- * 1. Pre-configured client with smart defaults (80% of users start here)
6
- * 2. FetchClient for custom configurations
7
- * 3. Individual middleware functions for specific needs
8
- * 4. Pre-built middleware stacks for common scenarios
9
- * 5. Types for TypeScript users
10
- */
11
- import { FetchClient } from './client/fetch-client';
12
- import { useProductionStack } from './middleware';
13
- /**
14
- * 🎯 PIT OF SUCCESS: Pre-configured fetch client (Level 1 - 80% of users)
15
- *
16
- * This client is ready to use out of the box with production-ready middleware:
17
- * - Authentication support (configure your token provider)
18
- * - Automatic retries with exponential backoff
19
- * - Response caching for GET requests
20
- * - Request/response logging
21
- * - Rate limiting protection
22
- * - Same-origin credentials for session-based auth (cookies)
23
- *
24
- * @example Just import and use:
25
- * ```typescript
26
- * import api from '@fgrzl/fetch';
27
- *
28
- * // Works immediately - no setup required!
29
- * const users = await api.get('/api/users');
30
- * const newUser = await api.post('/api/users', { name: 'John' });
31
- *
32
- * // With query parameters
33
- * const activeUsers = await api.get('/api/users', { status: 'active', limit: 10 });
34
- * ```
35
- *
36
- * @example Configure authentication:
37
- * ```typescript
38
- * import api from '@fgrzl/fetch';
39
- * import { useAuthentication } from '@fgrzl/fetch/middleware';
40
- *
41
- * const authClient = useAuthentication(api, {
42
- * tokenProvider: () => localStorage.getItem('auth-token') || ''
43
- * });
44
- * ```
45
- *
46
- * @example For token-only auth (no cookies):
47
- * ```typescript
48
- * import { FetchClient, useAuthentication } from '@fgrzl/fetch';
49
- *
50
- * const tokenClient = useAuthentication(new FetchClient({
51
- * credentials: 'omit' // Don't send cookies
52
- * }), {
53
- * tokenProvider: () => getJWTToken()
54
- * });
55
- * ```
56
- */
57
- const api = useProductionStack(new FetchClient({
1
+ // src/client/fetch-client.ts
2
+ var FetchClient = class {
3
+ constructor(config = {}) {
4
+ this.middlewares = [];
5
+ this.credentials = config.credentials ?? "same-origin";
6
+ }
7
+ use(middleware) {
8
+ this.middlewares.push(middleware);
9
+ return this;
10
+ }
11
+ async request(url, init = {}) {
12
+ let index = 0;
13
+ const execute = async (request) => {
14
+ const currentRequest = request || { ...init, url };
15
+ const currentUrl = currentRequest.url || url;
16
+ if (index >= this.middlewares.length) {
17
+ const { url: _, ...requestInit } = currentRequest;
18
+ return this.coreFetch(requestInit, currentUrl);
19
+ }
20
+ const middleware = this.middlewares[index++];
21
+ if (!middleware) {
22
+ const { url: _, ...requestInit } = currentRequest;
23
+ return this.coreFetch(requestInit, currentUrl);
24
+ }
25
+ return middleware(currentRequest, execute);
26
+ };
27
+ const result = await execute();
28
+ return result;
29
+ }
30
+ async coreFetch(request, url) {
31
+ try {
32
+ const finalInit = {
33
+ credentials: this.credentials,
34
+ ...request
35
+ };
36
+ if (finalInit.headers instanceof Headers) {
37
+ const headersObj = {};
38
+ finalInit.headers.forEach((value, key) => {
39
+ headersObj[key] = value;
40
+ });
41
+ finalInit.headers = headersObj;
42
+ }
43
+ const response = await fetch(url, finalInit);
44
+ const data = await this.parseResponse(response);
45
+ return {
46
+ data: response.ok ? data : null,
47
+ status: response.status,
48
+ statusText: response.statusText,
49
+ headers: response.headers,
50
+ url: response.url,
51
+ ok: response.ok,
52
+ ...response.ok ? {} : {
53
+ error: {
54
+ message: response.statusText,
55
+ body: data
56
+ }
57
+ }
58
+ };
59
+ } catch (error) {
60
+ if (error instanceof TypeError && error.message.includes("fetch")) {
61
+ return {
62
+ data: null,
63
+ status: 0,
64
+ statusText: "Network Error",
65
+ headers: new Headers(),
66
+ url,
67
+ ok: false,
68
+ error: {
69
+ message: "Failed to fetch",
70
+ body: error
71
+ }
72
+ };
73
+ }
74
+ throw error;
75
+ }
76
+ }
77
+ async parseResponse(res) {
78
+ const contentType = res.headers.get("content-type") || "";
79
+ if (contentType.includes("application/json")) {
80
+ return res.json();
81
+ }
82
+ if (contentType.includes("text/")) {
83
+ return res.text();
84
+ }
85
+ if (contentType.includes("application/octet-stream") || contentType.includes("image/") || contentType.includes("video/") || contentType.includes("audio/")) {
86
+ return res.blob();
87
+ }
88
+ if (res.body) {
89
+ const text = await res.text();
90
+ return text || null;
91
+ }
92
+ return null;
93
+ }
94
+ // Helper method to build URL with query parameters
95
+ buildUrlWithParams(url, params) {
96
+ if (!params) {
97
+ return url;
98
+ }
99
+ const urlObj = new URL(
100
+ url,
101
+ url.startsWith("http") ? void 0 : "http://localhost"
102
+ );
103
+ Object.entries(params).forEach(([key, value]) => {
104
+ if (value !== void 0 && value !== null) {
105
+ urlObj.searchParams.set(key, String(value));
106
+ }
107
+ });
108
+ if (!url.startsWith("http")) {
109
+ return urlObj.pathname + urlObj.search;
110
+ }
111
+ return urlObj.toString();
112
+ }
113
+ // 🎯 PIT OF SUCCESS: Convenience methods with smart defaults
114
+ /**
115
+ * HEAD request with query parameter support.
116
+ *
117
+ * HEAD requests are used to retrieve metadata about a resource without downloading
118
+ * the response body. Useful for checking if a resource exists, getting content length,
119
+ * last modified date, etc.
120
+ *
121
+ * @template T - Expected response data type (will be null for HEAD requests)
122
+ * @param url - Request URL
123
+ * @param params - Query parameters to append to URL
124
+ * @returns Promise resolving to typed response (data will always be null)
125
+ *
126
+ * @example Check if resource exists:
127
+ * ```typescript
128
+ * const headResponse = await client.head('/api/large-file.zip');
129
+ * if (headResponse.ok) {
130
+ * const contentLength = headResponse.headers.get('content-length');
131
+ * const lastModified = headResponse.headers.get('last-modified');
132
+ * console.log(`File size: ${contentLength} bytes`);
133
+ * }
134
+ * ```
135
+ *
136
+ * @example Check with query parameters:
137
+ * ```typescript
138
+ * const exists = await client.head('/api/users', { id: 123 });
139
+ * if (exists.status === 404) {
140
+ * console.log('User not found');
141
+ * }
142
+ * ```
143
+ */
144
+ head(url, params) {
145
+ const finalUrl = this.buildUrlWithParams(url, params);
146
+ return this.request(finalUrl, { method: "HEAD" });
147
+ }
148
+ /**
149
+ * HEAD request that returns useful metadata about a resource.
150
+ *
151
+ * This is a convenience method that extracts common metadata from HEAD responses
152
+ * for easier consumption.
153
+ *
154
+ * @param url - Request URL
155
+ * @param params - Query parameters to append to URL
156
+ * @returns Promise resolving to response with extracted metadata
157
+ *
158
+ * @example Get resource metadata:
159
+ * ```typescript
160
+ * const metadata = await client.headMetadata('/api/large-file.zip');
161
+ * if (metadata.ok) {
162
+ * console.log('File exists:', metadata.exists);
163
+ * console.log('Content type:', metadata.contentType);
164
+ * console.log('Size:', metadata.contentLength, 'bytes');
165
+ * console.log('Last modified:', metadata.lastModified);
166
+ * }
167
+ * ```
168
+ */
169
+ async headMetadata(url, params) {
170
+ const response = await this.head(url, params);
171
+ const contentLengthHeader = response.headers.get("content-length");
172
+ const lastModifiedHeader = response.headers.get("last-modified");
173
+ return {
174
+ ...response,
175
+ exists: response.ok,
176
+ contentType: response.headers.get("content-type") || void 0,
177
+ contentLength: contentLengthHeader ? parseInt(contentLengthHeader, 10) : void 0,
178
+ lastModified: lastModifiedHeader ? new Date(lastModifiedHeader) : void 0,
179
+ etag: response.headers.get("etag") || void 0,
180
+ cacheControl: response.headers.get("cache-control") || void 0
181
+ };
182
+ }
183
+ /**
184
+ * GET request with query parameter support.
185
+ *
186
+ * @template T - Expected response data type
187
+ * @param url - Request URL
188
+ * @param params - Query parameters to append to URL
189
+ * @returns Promise resolving to typed response
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * const users = await client.get<User[]>('/api/users');
194
+ * const filteredUsers = await client.get<User[]>('/api/users', { status: 'active', limit: 10 });
195
+ * if (users.ok) console.log(users.data);
196
+ * ```
197
+ */
198
+ get(url, params) {
199
+ const finalUrl = this.buildUrlWithParams(url, params);
200
+ return this.request(finalUrl, { method: "GET" });
201
+ }
202
+ /**
203
+ * POST request with automatic JSON serialization.
204
+ *
205
+ * @template T - Expected response data type
206
+ * @param url - Request URL
207
+ * @param body - Request body (auto-serialized to JSON)
208
+ * @param headers - Additional headers (Content-Type: application/json is default)
209
+ * @returns Promise resolving to typed response
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * const result = await client.post<User>('/api/users', { name: 'John' });
214
+ * ```
215
+ */
216
+ post(url, body, headers) {
217
+ const requestHeaders = {
218
+ "Content-Type": "application/json",
219
+ ...headers ?? {}
220
+ };
221
+ return this.request(url, {
222
+ method: "POST",
223
+ headers: requestHeaders,
224
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
225
+ });
226
+ }
227
+ /**
228
+ * PUT request with automatic JSON serialization.
229
+ *
230
+ * @template T - Expected response data type
231
+ * @param url - Request URL
232
+ * @param body - Request body (auto-serialized to JSON)
233
+ * @param headers - Additional headers (Content-Type: application/json is default)
234
+ * @returns Promise resolving to typed response
235
+ */
236
+ put(url, body, headers) {
237
+ const requestHeaders = {
238
+ "Content-Type": "application/json",
239
+ ...headers ?? {}
240
+ };
241
+ return this.request(url, {
242
+ method: "PUT",
243
+ headers: requestHeaders,
244
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
245
+ });
246
+ }
247
+ /**
248
+ * PATCH request with automatic JSON serialization.
249
+ *
250
+ * @template T - Expected response data type
251
+ * @param url - Request URL
252
+ * @param body - Request body (auto-serialized to JSON)
253
+ * @param headers - Additional headers (Content-Type: application/json is default)
254
+ * @returns Promise resolving to typed response
255
+ */
256
+ patch(url, body, headers) {
257
+ const requestHeaders = {
258
+ "Content-Type": "application/json",
259
+ ...headers ?? {}
260
+ };
261
+ return this.request(url, {
262
+ method: "PATCH",
263
+ headers: requestHeaders,
264
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
265
+ });
266
+ }
267
+ /**
268
+ * DELETE request with query parameter support.
269
+ *
270
+ * @template T - Expected response data type
271
+ * @param url - Request URL
272
+ * @param params - Query parameters to append to URL
273
+ * @returns Promise resolving to typed response
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * const result = await client.del('/api/users/123');
278
+ * const bulkResult = await client.del('/api/users', { status: 'inactive', force: true });
279
+ * if (result.ok) console.log('Deleted successfully');
280
+ * ```
281
+ */
282
+ del(url, params) {
283
+ const finalUrl = this.buildUrlWithParams(url, params);
284
+ return this.request(finalUrl, { method: "DELETE" });
285
+ }
286
+ };
287
+
288
+ // src/middleware/authentication/authentication.ts
289
+ function shouldSkipAuth(url, skipPatterns = []) {
290
+ return skipPatterns.some((pattern) => {
291
+ if (typeof pattern === "string") {
292
+ return url.includes(pattern);
293
+ }
294
+ return pattern.test(url);
295
+ });
296
+ }
297
+ function shouldIncludeAuth(url, includePatterns) {
298
+ if (!includePatterns || includePatterns.length === 0) {
299
+ return true;
300
+ }
301
+ return includePatterns.some((pattern) => {
302
+ if (typeof pattern === "string") {
303
+ return url.includes(pattern);
304
+ }
305
+ return pattern.test(url);
306
+ });
307
+ }
308
+ function createAuthenticationMiddleware(options) {
309
+ const {
310
+ tokenProvider,
311
+ headerName = "Authorization",
312
+ tokenType = "Bearer",
313
+ skipPatterns = [],
314
+ includePatterns
315
+ } = options;
316
+ return async (request, next) => {
317
+ const url = request.url || "";
318
+ const parsedUrl = new URL(url);
319
+ const pathname = parsedUrl.pathname;
320
+ if (shouldSkipAuth(pathname, skipPatterns) || !shouldIncludeAuth(pathname, includePatterns)) {
321
+ return next(request);
322
+ }
323
+ try {
324
+ const token = await tokenProvider();
325
+ if (!token) {
326
+ return next(request);
327
+ }
328
+ const headers = new Headers(request.headers);
329
+ headers.set(headerName, `${tokenType} ${token}`);
330
+ const modifiedRequest = {
331
+ ...request,
332
+ headers
333
+ };
334
+ return next(modifiedRequest);
335
+ } catch {
336
+ return next(request);
337
+ }
338
+ };
339
+ }
340
+
341
+ // src/middleware/authentication/index.ts
342
+ function useAuthentication(client, options) {
343
+ return client.use(createAuthenticationMiddleware(options));
344
+ }
345
+
346
+ // src/middleware/authorization/authorization.ts
347
+ function createRedirectHandler(config = {}) {
348
+ const {
349
+ redirectPath = "/login",
350
+ returnUrlParam = "return_url",
351
+ includeReturnUrl = true
352
+ } = config;
353
+ return () => {
354
+ let redirectUrl = redirectPath;
355
+ if (includeReturnUrl && typeof window !== "undefined") {
356
+ const currentUrl = encodeURIComponent(window.location.href);
357
+ const separator = redirectPath.includes("?") ? "&" : "?";
358
+ redirectUrl = `${redirectPath}${separator}${returnUrlParam}=${currentUrl}`;
359
+ }
360
+ if (typeof window !== "undefined") {
361
+ window.location.href = redirectUrl;
362
+ }
363
+ };
364
+ }
365
+ function selectUnauthorizedHandler(providedHandler, redirectConfig) {
366
+ if (providedHandler) {
367
+ return providedHandler;
368
+ }
369
+ return createRedirectHandler(redirectConfig);
370
+ }
371
+ function shouldSkipAuth2(url, skipPatterns = []) {
372
+ let pathname;
373
+ try {
374
+ pathname = new URL(url).pathname;
375
+ } catch {
376
+ pathname = url;
377
+ }
378
+ return skipPatterns.some((pattern) => {
379
+ if (typeof pattern === "string") {
380
+ return pathname.includes(pattern);
381
+ }
382
+ return pattern.test(pathname);
383
+ });
384
+ }
385
+ function createAuthorizationMiddleware(options = {}) {
386
+ const {
387
+ onUnauthorized: providedOnUnauthorized,
388
+ redirectConfig,
389
+ onForbidden,
390
+ skipPatterns = [],
391
+ statusCodes = [401]
392
+ } = options;
393
+ const onUnauthorized = selectUnauthorizedHandler(
394
+ providedOnUnauthorized,
395
+ redirectConfig
396
+ );
397
+ return async (request, next) => {
398
+ const url = request.url || "";
399
+ if (shouldSkipAuth2(url, skipPatterns)) {
400
+ return next(request);
401
+ }
402
+ const response = await next(request);
403
+ if (statusCodes.includes(response.status)) {
404
+ try {
405
+ if (response.status === 401 && onUnauthorized) {
406
+ await onUnauthorized(response, request);
407
+ } else if (response.status === 403 && onForbidden) {
408
+ await onForbidden(response, request);
409
+ } else if (onUnauthorized) {
410
+ await onUnauthorized(response, request);
411
+ }
412
+ } catch (error) {
413
+ console.warn("Authorization handler failed:", error);
414
+ }
415
+ }
416
+ return response;
417
+ };
418
+ }
419
+
420
+ // src/middleware/authorization/index.ts
421
+ function useAuthorization(client, options = {}) {
422
+ return client.use(createAuthorizationMiddleware(options));
423
+ }
424
+
425
+ // src/middleware/cache/cache.ts
426
+ var MemoryStorage = class {
427
+ constructor() {
428
+ this.cache = /* @__PURE__ */ new Map();
429
+ }
430
+ async get(key) {
431
+ const entry = this.cache.get(key);
432
+ if (!entry) {
433
+ return null;
434
+ }
435
+ if (Date.now() > entry.expiresAt) {
436
+ this.cache.delete(key);
437
+ return null;
438
+ }
439
+ return entry;
440
+ }
441
+ async getWithExpiry(key) {
442
+ const entry = this.cache.get(key);
443
+ if (!entry) {
444
+ return { entry: null, isExpired: false };
445
+ }
446
+ const isExpired = Date.now() > entry.expiresAt;
447
+ return { entry, isExpired };
448
+ }
449
+ async set(key, entry) {
450
+ this.cache.set(key, entry);
451
+ }
452
+ async delete(key) {
453
+ this.cache.delete(key);
454
+ }
455
+ async clear() {
456
+ this.cache.clear();
457
+ }
458
+ };
459
+ var defaultKeyGenerator = (request) => {
460
+ const url = request.url || "";
461
+ const method = request.method || "GET";
462
+ const headers = request.headers ? JSON.stringify(request.headers) : "";
463
+ return `${method}:${url}:${headers}`;
464
+ };
465
+ function shouldSkipCache(url, skipPatterns = []) {
466
+ return skipPatterns.some((pattern) => {
467
+ if (typeof pattern === "string") {
468
+ return url.includes(pattern);
469
+ }
470
+ return pattern.test(url);
471
+ });
472
+ }
473
+ function createCacheMiddleware(options = {}) {
474
+ const {
475
+ ttl = 5 * 60 * 1e3,
476
+ // 5 minutes
477
+ methods = ["GET"],
478
+ storage = new MemoryStorage(),
479
+ keyGenerator = defaultKeyGenerator,
480
+ skipPatterns = [],
481
+ staleWhileRevalidate = false
482
+ } = options;
483
+ return async (request, next) => {
484
+ const method = (request.method || "GET").toUpperCase();
485
+ const url = request.url || "";
486
+ if (!methods.includes(method) || shouldSkipCache(url, skipPatterns)) {
487
+ return next(request);
488
+ }
489
+ const cacheKey = keyGenerator(request);
490
+ try {
491
+ const { entry: cached, isExpired } = storage.getWithExpiry ? await storage.getWithExpiry(cacheKey) : await (async () => {
492
+ const entry = await storage.get(cacheKey);
493
+ return { entry, isExpired: false };
494
+ })();
495
+ if (cached && !isExpired) {
496
+ return {
497
+ ...cached.response,
498
+ headers: new Headers(cached.response.headers),
499
+ data: cached.response.data
500
+ };
501
+ }
502
+ if (cached && staleWhileRevalidate) {
503
+ const cachedResponse = {
504
+ ...cached.response,
505
+ headers: new Headers(cached.response.headers),
506
+ data: cached.response.data
507
+ };
508
+ if (isExpired) {
509
+ next(request).then(async (freshResponse) => {
510
+ const headersObj = {};
511
+ freshResponse.headers.forEach((value, key) => {
512
+ headersObj[key] = value;
513
+ });
514
+ const cacheEntry = {
515
+ response: {
516
+ status: freshResponse.status,
517
+ statusText: freshResponse.statusText,
518
+ headers: headersObj,
519
+ data: freshResponse.data
520
+ },
521
+ timestamp: Date.now(),
522
+ expiresAt: Date.now() + ttl
523
+ };
524
+ await storage.set(cacheKey, cacheEntry);
525
+ }).catch(() => {
526
+ });
527
+ }
528
+ return cachedResponse;
529
+ }
530
+ const response = await next(request);
531
+ if (response.ok) {
532
+ try {
533
+ const headersObj = {};
534
+ response.headers.forEach((value, key) => {
535
+ headersObj[key] = value;
536
+ });
537
+ const cacheEntry = {
538
+ response: {
539
+ status: response.status,
540
+ statusText: response.statusText,
541
+ headers: headersObj,
542
+ data: response.data
543
+ },
544
+ timestamp: Date.now(),
545
+ expiresAt: Date.now() + ttl
546
+ };
547
+ await storage.set(cacheKey, cacheEntry);
548
+ } catch {
549
+ }
550
+ }
551
+ return response;
552
+ } catch (error) {
553
+ if (error && typeof error === "object" && "message" in error) {
554
+ const errorMessage = error.message;
555
+ if (errorMessage.includes("Network") || errorMessage.includes("fetch")) {
556
+ throw error;
557
+ }
558
+ }
559
+ return next(request);
560
+ }
561
+ };
562
+ }
563
+
564
+ // src/middleware/cache/index.ts
565
+ function useCache(client, options = {}) {
566
+ return client.use(createCacheMiddleware(options));
567
+ }
568
+
569
+ // src/middleware/csrf/csrf.ts
570
+ function getTokenFromCookie(cookieName = "XSRF-TOKEN") {
571
+ if (typeof document === "undefined") {
572
+ return "";
573
+ }
574
+ const name = `${cookieName}=`;
575
+ const decodedCookie = decodeURIComponent(document.cookie);
576
+ const cookies = decodedCookie.split(";");
577
+ for (const cookie of cookies) {
578
+ const c = cookie.trim();
579
+ if (c.indexOf(name) === 0) {
580
+ return c.substring(name.length);
581
+ }
582
+ }
583
+ return "";
584
+ }
585
+ function shouldSkipCSRF(url, skipPatterns = []) {
586
+ return skipPatterns.some((pattern) => {
587
+ if (typeof pattern === "string") {
588
+ return url.includes(pattern);
589
+ }
590
+ return pattern.test(url);
591
+ });
592
+ }
593
+ function createCSRFMiddleware(options = {}) {
594
+ const {
595
+ headerName = "X-XSRF-TOKEN",
596
+ cookieName = "XSRF-TOKEN",
597
+ protectedMethods = ["POST", "PUT", "PATCH", "DELETE"],
598
+ skipPatterns = [],
599
+ tokenProvider = () => getTokenFromCookie(cookieName)
600
+ } = options;
601
+ return async (request, next) => {
602
+ const method = (request.method || "GET").toUpperCase();
603
+ const url = request.url || "";
604
+ if (!protectedMethods.includes(method) || shouldSkipCSRF(url, skipPatterns)) {
605
+ return next(request);
606
+ }
607
+ const token = tokenProvider();
608
+ if (!token) {
609
+ return next(request);
610
+ }
611
+ const headers = new Headers(request.headers);
612
+ headers.set(headerName, token);
613
+ const modifiedRequest = {
614
+ ...request,
615
+ headers
616
+ };
617
+ return next(modifiedRequest);
618
+ };
619
+ }
620
+
621
+ // src/middleware/csrf/index.ts
622
+ function useCSRF(client, options = {}) {
623
+ return client.use(createCSRFMiddleware(options));
624
+ }
625
+
626
+ // src/middleware/logging/logging.ts
627
+ var defaultLogger = {
628
+ // eslint-disable-next-line no-console -- allow console.debug in logger implementation
629
+ debug: (message, data) => console.debug(message, data),
630
+ // eslint-disable-next-line no-console -- allow console.info in logger implementation
631
+ info: (message, data) => console.info(message, data),
632
+ // eslint-disable-next-line no-console -- allow console.warn in logger implementation
633
+ warn: (message, data) => console.warn(message, data),
634
+ // eslint-disable-next-line no-console -- allow console.error in logger implementation
635
+ error: (message, data) => console.error(message, data)
636
+ };
637
+ var LOG_LEVELS = {
638
+ debug: 0,
639
+ info: 1,
640
+ warn: 2,
641
+ error: 3
642
+ };
643
+ var defaultFormatter = (entry) => {
644
+ const { method, url, status, duration } = entry;
645
+ let message = `${method} ${url}`;
646
+ if (status) {
647
+ message += ` \u2192 ${status}`;
648
+ }
649
+ if (duration) {
650
+ message += ` (${duration}ms)`;
651
+ }
652
+ return message;
653
+ };
654
+ function shouldSkipLogging(url, skipPatterns = []) {
655
+ return skipPatterns.some((pattern) => {
656
+ if (typeof pattern === "string") {
657
+ return url.includes(pattern);
658
+ }
659
+ return pattern.test(url);
660
+ });
661
+ }
662
+ function createLoggingMiddleware(options = {}) {
663
+ const {
664
+ level = "info",
665
+ logger = defaultLogger,
666
+ includeRequestHeaders = false,
667
+ includeResponseHeaders = false,
668
+ includeRequestBody = false,
669
+ includeResponseBody = false,
670
+ skipPatterns = [],
671
+ formatter = defaultFormatter
672
+ } = options;
673
+ const minLevel = LOG_LEVELS[level];
674
+ return async (request, next) => {
675
+ const url = request.url || "";
676
+ const method = (request.method || "GET").toUpperCase();
677
+ if (shouldSkipLogging(url, skipPatterns)) {
678
+ return next(request);
679
+ }
680
+ const startTime = Date.now();
681
+ if (LOG_LEVELS.debug >= minLevel) {
682
+ const requestHeaders = includeRequestHeaders ? getHeadersObject(
683
+ request.headers
684
+ ) : void 0;
685
+ const requestBody = includeRequestBody ? request.body : void 0;
686
+ const requestEntry = {
687
+ level: "debug",
688
+ timestamp: startTime,
689
+ method,
690
+ url,
691
+ ...requestHeaders && { requestHeaders },
692
+ ...requestBody && { requestBody }
693
+ };
694
+ logger.debug(`\u2192 ${formatter(requestEntry)}`, requestEntry);
695
+ }
696
+ try {
697
+ const response = await next(request);
698
+ const duration = Date.now() - startTime;
699
+ const logLevel = response.status >= 400 ? "error" : "info";
700
+ if (LOG_LEVELS[logLevel] >= minLevel) {
701
+ const responseHeaders = includeResponseHeaders ? getHeadersObject(response.headers) : void 0;
702
+ const responseBody = includeResponseBody ? response.data : void 0;
703
+ const responseEntry = {
704
+ level: logLevel,
705
+ timestamp: Date.now(),
706
+ method,
707
+ url,
708
+ status: response.status,
709
+ duration,
710
+ ...responseHeaders ? { responseHeaders } : {},
711
+ ...responseBody !== void 0 ? { responseBody } : {}
712
+ };
713
+ const logMessage = `\u2190 ${formatter(responseEntry)}`;
714
+ if (logLevel === "error") {
715
+ logger.error(logMessage, responseEntry);
716
+ } else {
717
+ logger.info(logMessage, responseEntry);
718
+ }
719
+ }
720
+ return response;
721
+ } catch (error) {
722
+ const duration = Date.now() - startTime;
723
+ if (LOG_LEVELS.error >= minLevel) {
724
+ const errorEntry = {
725
+ level: "error",
726
+ timestamp: Date.now(),
727
+ method,
728
+ url,
729
+ duration,
730
+ error: error instanceof Error ? error : new Error(String(error))
731
+ };
732
+ logger.error(`\u2717 ${formatter(errorEntry)}`, errorEntry);
733
+ }
734
+ throw error;
735
+ }
736
+ };
737
+ }
738
+ function getHeadersObject(headers) {
739
+ if (!headers) {
740
+ return void 0;
741
+ }
742
+ const obj = {};
743
+ if (headers instanceof Headers) {
744
+ headers.forEach((value, key) => {
745
+ obj[key] = value;
746
+ });
747
+ return obj;
748
+ } else {
749
+ return headers;
750
+ }
751
+ }
752
+
753
+ // src/middleware/logging/index.ts
754
+ function useLogging(client, options = {}) {
755
+ return client.use(createLoggingMiddleware(options));
756
+ }
757
+
758
+ // src/middleware/rate-limit/rate-limit.ts
759
+ var TokenBucket = class {
760
+ constructor(maxTokens, refillRate, timeProvider = () => Date.now()) {
761
+ this.maxTokens = maxTokens;
762
+ this.refillRate = refillRate;
763
+ this.timeProvider = timeProvider;
764
+ this.tokens = maxTokens;
765
+ this.lastRefill = this.timeProvider();
766
+ }
767
+ tryConsume() {
768
+ this.refill();
769
+ if (this.tokens >= 1) {
770
+ this.tokens--;
771
+ return { allowed: true };
772
+ }
773
+ const retryAfter = (1 - this.tokens) / this.refillRate;
774
+ return { allowed: false, retryAfter: Math.ceil(retryAfter) };
775
+ }
776
+ refill() {
777
+ const now = this.timeProvider();
778
+ const timePassed = now - this.lastRefill;
779
+ const tokensToAdd = timePassed * this.refillRate;
780
+ this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
781
+ this.lastRefill = now;
782
+ }
783
+ };
784
+ function createRateLimitMiddleware(options = {}) {
785
+ const {
786
+ maxRequests = 60,
787
+ windowMs = 6e4,
788
+ keyGenerator = () => "default",
789
+ skipPatterns = [],
790
+ onRateLimitExceeded
791
+ } = options;
792
+ const buckets = /* @__PURE__ */ new Map();
793
+ const refillRate = maxRequests / windowMs;
794
+ return async (request, next) => {
795
+ const url = request.url || "";
796
+ if (skipPatterns.some(
797
+ (pattern) => typeof pattern === "string" ? url.includes(pattern) : pattern.test(url)
798
+ )) {
799
+ return next(request);
800
+ }
801
+ const key = keyGenerator(request);
802
+ if (!buckets.has(key)) {
803
+ buckets.set(key, new TokenBucket(maxRequests, refillRate));
804
+ }
805
+ const bucket = buckets.get(key);
806
+ const result = bucket.tryConsume();
807
+ if (!result.allowed) {
808
+ if (onRateLimitExceeded) {
809
+ const customResponse = await onRateLimitExceeded(
810
+ result.retryAfter || 0,
811
+ request
812
+ );
813
+ if (customResponse) {
814
+ return customResponse;
815
+ }
816
+ }
817
+ return {
818
+ data: null,
819
+ status: 429,
820
+ statusText: "Too Many Requests",
821
+ headers: new Headers({
822
+ "Retry-After": Math.ceil((result.retryAfter || 0) / 1e3).toString()
823
+ }),
824
+ url: request.url || "",
825
+ ok: false,
826
+ error: {
827
+ message: `Rate limit exceeded. Retry after ${result.retryAfter}ms`,
828
+ body: { retryAfter: result.retryAfter }
829
+ }
830
+ };
831
+ }
832
+ return next(request);
833
+ };
834
+ }
835
+
836
+ // src/middleware/rate-limit/index.ts
837
+ function useRateLimit(client, options = {}) {
838
+ return client.use(createRateLimitMiddleware(options));
839
+ }
840
+
841
+ // src/middleware/retry/retry.ts
842
+ var defaultShouldRetry = (response) => {
843
+ return response.status === 0 || response.status >= 500 && response.status < 600;
844
+ };
845
+ var calculateDelay = (attempt, baseDelay, backoff, maxDelay) => {
846
+ let delay;
847
+ switch (backoff) {
848
+ case "exponential":
849
+ delay = baseDelay * Math.pow(2, attempt - 1);
850
+ break;
851
+ case "linear":
852
+ delay = baseDelay * attempt;
853
+ break;
854
+ case "fixed":
855
+ default:
856
+ delay = baseDelay;
857
+ break;
858
+ }
859
+ return Math.min(delay, maxDelay);
860
+ };
861
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
862
+ function createRetryMiddleware(options = {}) {
863
+ const {
864
+ maxRetries = 3,
865
+ delay = 1e3,
866
+ backoff = "exponential",
867
+ maxDelay = 3e4,
868
+ shouldRetry = defaultShouldRetry,
869
+ onRetry
870
+ } = options;
871
+ return async (request, next) => {
872
+ let lastResponse;
873
+ let attempt = 0;
874
+ while (attempt <= maxRetries) {
875
+ try {
876
+ const response = await next(request);
877
+ if (response.ok) {
878
+ return response;
879
+ }
880
+ if (!shouldRetry(
881
+ { status: response.status, ok: response.ok },
882
+ attempt + 1
883
+ )) {
884
+ return response;
885
+ }
886
+ if (attempt >= maxRetries) {
887
+ return response;
888
+ }
889
+ lastResponse = response;
890
+ attempt++;
891
+ const retryDelay = calculateDelay(attempt, delay, backoff, maxDelay);
892
+ if (onRetry) {
893
+ onRetry(attempt, retryDelay, {
894
+ status: response.status,
895
+ statusText: response.statusText
896
+ });
897
+ }
898
+ await sleep(retryDelay);
899
+ } catch (error) {
900
+ const errorResponse = {
901
+ data: null,
902
+ status: 0,
903
+ statusText: "Network Error",
904
+ headers: new Headers(),
905
+ url: request.url || "",
906
+ ok: false,
907
+ error: {
908
+ message: error instanceof Error ? error.message : "Unknown error",
909
+ body: error
910
+ }
911
+ };
912
+ if (!shouldRetry(errorResponse, attempt + 1)) {
913
+ return errorResponse;
914
+ }
915
+ if (attempt >= maxRetries) {
916
+ return errorResponse;
917
+ }
918
+ lastResponse = errorResponse;
919
+ attempt++;
920
+ const retryDelay = calculateDelay(attempt, delay, backoff, maxDelay);
921
+ if (onRetry) {
922
+ onRetry(attempt, retryDelay, {
923
+ status: errorResponse.status,
924
+ statusText: errorResponse.statusText
925
+ });
926
+ }
927
+ await sleep(retryDelay);
928
+ }
929
+ }
930
+ return lastResponse;
931
+ };
932
+ }
933
+
934
+ // src/middleware/retry/index.ts
935
+ function useRetry(client, options = {}) {
936
+ return client.use(createRetryMiddleware(options));
937
+ }
938
+
939
+ // src/middleware/index.ts
940
+ function useProductionStack(client, config = {}) {
941
+ let enhanced = client;
942
+ if (config.auth) {
943
+ enhanced = useAuthentication(enhanced, config.auth);
944
+ }
945
+ if (config.cache !== void 0) {
946
+ enhanced = useCache(enhanced, config.cache);
947
+ }
948
+ if (config.retry !== void 0) {
949
+ enhanced = useRetry(enhanced, config.retry);
950
+ }
951
+ if (config.rateLimit !== void 0) {
952
+ enhanced = useRateLimit(enhanced, config.rateLimit);
953
+ }
954
+ if (config.logging !== void 0) {
955
+ enhanced = useLogging(enhanced, config.logging);
956
+ }
957
+ return enhanced;
958
+ }
959
+ function useDevelopmentStack(client, config = {}) {
960
+ let enhanced = client;
961
+ if (config.auth) {
962
+ enhanced = useAuthentication(enhanced, config.auth);
963
+ }
964
+ enhanced = useRetry(enhanced, {
965
+ maxRetries: 1,
966
+ delay: 100
967
+ });
968
+ enhanced = useLogging(enhanced, {
969
+ level: "debug",
970
+ includeRequestHeaders: true,
971
+ includeResponseHeaders: true,
972
+ includeRequestBody: true,
973
+ includeResponseBody: true
974
+ });
975
+ return enhanced;
976
+ }
977
+ function useBasicStack(client, config) {
978
+ return useRetry(useAuthentication(client, config.auth), { maxRetries: 2 });
979
+ }
980
+
981
+ // src/errors/index.ts
982
+ var FetchError = class extends Error {
983
+ /**
984
+ * Creates a new FetchError.
985
+ * @param message - Error message
986
+ * @param cause - Optional underlying cause
987
+ */
988
+ constructor(message, cause) {
989
+ super(message);
990
+ this.name = "FetchError";
991
+ if (cause !== void 0) {
992
+ this.cause = cause;
993
+ }
994
+ }
995
+ };
996
+ var HttpError = class extends FetchError {
997
+ /**
998
+ * Creates a new HttpError.
999
+ * @param status - HTTP status code
1000
+ * @param statusText - HTTP status text
1001
+ * @param body - Response body
1002
+ * @param url - The request URL
1003
+ */
1004
+ constructor(status, statusText, body, url) {
1005
+ super(`HTTP ${status} ${statusText} at ${url}`);
1006
+ this.name = "HttpError";
1007
+ this.status = status;
1008
+ this.statusText = statusText;
1009
+ this.body = body;
1010
+ }
1011
+ };
1012
+ var NetworkError = class extends FetchError {
1013
+ /**
1014
+ * Creates a new NetworkError.
1015
+ * @param message - Error message
1016
+ * @param url - The request URL
1017
+ * @param cause - The underlying network error
1018
+ */
1019
+ constructor(message, url, cause) {
1020
+ super(`Network error for ${url}: ${message}`, cause);
1021
+ this.name = "NetworkError";
1022
+ }
1023
+ };
1024
+
1025
+ // src/index.ts
1026
+ var api = useProductionStack(
1027
+ new FetchClient({
58
1028
  // Smart default: include cookies for session-based auth
59
1029
  // Can be overridden by creating a custom FetchClient
60
- credentials: 'same-origin',
61
- }), {
1030
+ credentials: "same-origin"
1031
+ }),
1032
+ {
62
1033
  // Smart defaults - users can override as needed
63
1034
  retry: {
64
- maxRetries: 2,
65
- delay: 1000,
1035
+ maxRetries: 2,
1036
+ delay: 1e3
66
1037
  },
67
1038
  cache: {
68
- ttl: 5 * 60 * 1000, // 5 minutes
69
- methods: ['GET'],
1039
+ ttl: 5 * 60 * 1e3,
1040
+ // 5 minutes
1041
+ methods: ["GET"]
70
1042
  },
71
1043
  logging: {
72
- level: 'info',
1044
+ level: "info"
73
1045
  },
74
1046
  rateLimit: {
75
- maxRequests: 100,
76
- windowMs: 60 * 1000, // 100 requests per minute
77
- },
78
- });
79
- // 🎯 LEVEL 1: Export the production-ready client as default
80
- export default api;
81
- // 🎯 LEVEL 2: FetchClient for custom configurations
82
- export { FetchClient } from './client/fetch-client';
83
- export { FetchError, HttpError, NetworkError } from './errors';
84
- // 🎯 LEVEL 3: Individual middleware functions (import from our comprehensive middleware index)
85
- export {
86
- // Authentication
87
- useAuthentication, createAuthenticationMiddleware,
88
- // Authorization
89
- useAuthorization, createAuthorizationMiddleware,
90
- // Cache
91
- useCache, createCacheMiddleware,
92
- // CSRF
93
- useCSRF,
94
- // Logging
95
- useLogging, createLoggingMiddleware,
96
- // Rate Limiting
97
- useRateLimit, createRateLimitMiddleware,
98
- // Retry
99
- useRetry, createRetryMiddleware, } from './middleware';
100
- // 🎯 LEVEL 4: Pre-built middleware stacks for common scenarios
101
- export { useProductionStack, useDevelopmentStack, useBasicStack, } from './middleware';
1047
+ maxRequests: 100,
1048
+ windowMs: 60 * 1e3
1049
+ // 100 requests per minute
1050
+ }
1051
+ }
1052
+ );
1053
+ var index_default = api;
1054
+ export {
1055
+ FetchClient,
1056
+ FetchError,
1057
+ HttpError,
1058
+ NetworkError,
1059
+ createAuthenticationMiddleware,
1060
+ createAuthorizationMiddleware,
1061
+ createCacheMiddleware,
1062
+ createLoggingMiddleware,
1063
+ createRateLimitMiddleware,
1064
+ createRetryMiddleware,
1065
+ index_default as default,
1066
+ useAuthentication,
1067
+ useAuthorization,
1068
+ useBasicStack,
1069
+ useCSRF,
1070
+ useCache,
1071
+ useDevelopmentStack,
1072
+ useLogging,
1073
+ useProductionStack,
1074
+ useRateLimit,
1075
+ useRetry
1076
+ };
102
1077
  //# sourceMappingURL=index.js.map