@fgrzl/fetch 1.1.0-alpha.8 → 1.2.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 +90 -20
  4. package/dist/cjs/index.js +1168 -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 +1428 -10
  9. package/dist/index.js +1124 -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.d.ts CHANGED
@@ -1,3 +1,1428 @@
1
+ /**
2
+ * @fileoverview Type definitions for the HTTP client.
3
+ *
4
+ * This file contains core TypeScript interfaces and types for FetchClient.
5
+ * Designed for discoverability and type safety.
6
+ */
7
+ /**
8
+ * Typed response wrapper with consistent shape.
9
+ *
10
+ * ✅ Always returns this shape (never throws)
11
+ * ✅ Use `.ok` to check success
12
+ * ✅ Use `.data` for parsed response
13
+ * ✅ Use `.error` for failure details
14
+ *
15
+ * @template T - The expected type of the response data
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const result = await client.get<User[]>('/api/users');
20
+ * if (result.ok) {
21
+ * console.log(result.data); // Type is User[]
22
+ * } else {
23
+ * console.error(result.error?.message); // Handle error
24
+ * }
25
+ * ```
26
+ */
27
+ interface FetchResponse<T> {
28
+ /** The parsed response data (null if request failed) */
29
+ data: T | null;
30
+ /** HTTP status code (0 for network errors) */
31
+ status: number;
32
+ /** HTTP status text ('Network Error' for network failures) */
33
+ statusText: string;
34
+ /** Response headers */
35
+ headers: Headers;
36
+ /** The request URL */
37
+ url: string;
38
+ /** True if status 200-299, false otherwise */
39
+ ok: boolean;
40
+ /** Error details when ok is false */
41
+ error?: {
42
+ /** Human-readable error message */
43
+ message: string;
44
+ /** Raw error response body */
45
+ body?: unknown;
46
+ };
47
+ }
48
+ /**
49
+ * Configuration options for FetchClient.
50
+ *
51
+ * Optimized for "pit of success" - good defaults, minimal required config.
52
+ */
53
+ interface FetchClientOptions {
54
+ /**
55
+ * Controls credential handling for requests.
56
+ *
57
+ * - 'same-origin' (default): Send cookies for same-origin requests
58
+ * - 'include': Always send cookies
59
+ * - 'omit': Never send cookies
60
+ */
61
+ credentials?: RequestCredentials;
62
+ /**
63
+ * Base URL for relative requests.
64
+ *
65
+ * When set, all relative URLs (not starting with http:// or https://) will be
66
+ * prefixed with this base URL. Absolute URLs are used as-is.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const client = new FetchClient({ baseUrl: 'https://api.example.com' });
71
+ * await client.get('/users'); // → GET https://api.example.com/users
72
+ * await client.get('https://other-api.com/data'); // → GET https://other-api.com/data
73
+ * ```
74
+ */
75
+ baseUrl?: string;
76
+ }
77
+
78
+ /**
79
+ * @fileoverview Enhanced fetch client with intercept middleware architecture.
80
+ */
81
+
82
+ /**
83
+ * Intercept middleware type that allows full control over request/response cycle.
84
+ * Middleware can modify requests, handle responses, implement retries, etc.
85
+ */
86
+ type FetchMiddleware = (request: RequestInit & {
87
+ url?: string;
88
+ }, next: (modifiedRequest?: RequestInit & {
89
+ url?: string;
90
+ }) => Promise<FetchResponse<unknown>>) => Promise<FetchResponse<unknown>>;
91
+ /**
92
+ * Enhanced HTTP client with intercept middleware architecture.
93
+ *
94
+ * Features:
95
+ * - 🎯 Smart defaults (JSON content-type, same-origin credentials)
96
+ * - 🔧 Powerful middleware system for cross-cutting concerns
97
+ * - 🛡️ Consistent error handling (never throws, always returns response)
98
+ * - 📦 TypeScript-first with full type inference
99
+ * - 🚀 Modern async/await API
100
+ *
101
+ * @example Basic usage:
102
+ * ```typescript
103
+ * const client = new FetchClient();
104
+ *
105
+ * // GET request - just works
106
+ * const users = await client.get<User[]>('/api/users');
107
+ * if (users.ok) {
108
+ * console.log(users.data); // Type is User[]
109
+ * }
110
+ *
111
+ * // POST request - JSON by default
112
+ * const result = await client.post('/api/users', { name: 'John' });
113
+ * ```
114
+ *
115
+ * @example With middleware:
116
+ * ```typescript
117
+ * const client = new FetchClient();
118
+ *
119
+ * // Add auth middleware
120
+ * client.use((request, next) => {
121
+ * request.headers = { ...request.headers, Authorization: 'Bearer token' };
122
+ * return next(request);
123
+ * });
124
+ *
125
+ * // Now all requests include auth
126
+ * const data = await client.get('/api/protected');
127
+ * ```
128
+ */
129
+ declare class FetchClient {
130
+ private middlewares;
131
+ private credentials;
132
+ private baseUrl;
133
+ constructor(config?: FetchClientOptions);
134
+ use(middleware: FetchMiddleware): this;
135
+ /**
136
+ * Set or update the base URL for this client instance.
137
+ *
138
+ * When a base URL is set, relative URLs will be resolved against it.
139
+ * Absolute URLs will continue to work unchanged.
140
+ *
141
+ * @param baseUrl - The base URL to set, or undefined to clear it
142
+ * @returns The client instance for method chaining
143
+ *
144
+ * @example Set base URL:
145
+ * ```typescript
146
+ * const client = new FetchClient();
147
+ * client.setBaseUrl('https://api.example.com');
148
+ *
149
+ * // Now relative URLs work
150
+ * await client.get('/users'); // → GET https://api.example.com/users
151
+ * ```
152
+ *
153
+ * @example Chain with middleware:
154
+ * ```typescript
155
+ * const client = useProductionStack(new FetchClient())
156
+ * .setBaseUrl(process.env.API_BASE_URL);
157
+ * ```
158
+ */
159
+ setBaseUrl(baseUrl?: string): this;
160
+ request<T = unknown>(url: string, init?: RequestInit): Promise<FetchResponse<T>>;
161
+ private coreFetch;
162
+ private parseResponse;
163
+ private buildUrlWithParams;
164
+ /**
165
+ * Resolves a URL with the base URL if it's relative and base URL is configured
166
+ * @param url - The URL to resolve
167
+ * @returns The resolved URL
168
+ * @private
169
+ */
170
+ private resolveUrl;
171
+ /**
172
+ * HEAD request with query parameter support.
173
+ *
174
+ * HEAD requests are used to retrieve metadata about a resource without downloading
175
+ * the response body. Useful for checking if a resource exists, getting content length,
176
+ * last modified date, etc.
177
+ *
178
+ * @template T - Expected response data type (will be null for HEAD requests)
179
+ * @param url - Request URL
180
+ * @param params - Query parameters to append to URL
181
+ * @returns Promise resolving to typed response (data will always be null)
182
+ *
183
+ * @example Check if resource exists:
184
+ * ```typescript
185
+ * const headResponse = await client.head('/api/large-file.zip');
186
+ * if (headResponse.ok) {
187
+ * const contentLength = headResponse.headers.get('content-length');
188
+ * const lastModified = headResponse.headers.get('last-modified');
189
+ * console.log(`File size: ${contentLength} bytes`);
190
+ * }
191
+ * ```
192
+ *
193
+ * @example Check with query parameters:
194
+ * ```typescript
195
+ * const exists = await client.head('/api/users', { id: 123 });
196
+ * if (exists.status === 404) {
197
+ * console.log('User not found');
198
+ * }
199
+ * ```
200
+ */
201
+ head<T = null>(url: string, params?: Record<string, string | number | boolean | undefined>): Promise<FetchResponse<T>>;
202
+ /**
203
+ * HEAD request that returns useful metadata about a resource.
204
+ *
205
+ * This is a convenience method that extracts common metadata from HEAD responses
206
+ * for easier consumption.
207
+ *
208
+ * @param url - Request URL
209
+ * @param params - Query parameters to append to URL
210
+ * @returns Promise resolving to response with extracted metadata
211
+ *
212
+ * @example Get resource metadata:
213
+ * ```typescript
214
+ * const metadata = await client.headMetadata('/api/large-file.zip');
215
+ * if (metadata.ok) {
216
+ * console.log('File exists:', metadata.exists);
217
+ * console.log('Content type:', metadata.contentType);
218
+ * console.log('Size:', metadata.contentLength, 'bytes');
219
+ * console.log('Last modified:', metadata.lastModified);
220
+ * }
221
+ * ```
222
+ */
223
+ headMetadata(url: string, params?: Record<string, string | number | boolean | undefined>): Promise<FetchResponse<null> & {
224
+ exists: boolean;
225
+ contentType: string | undefined;
226
+ contentLength: number | undefined;
227
+ lastModified: Date | undefined;
228
+ etag: string | undefined;
229
+ cacheControl: string | undefined;
230
+ }>;
231
+ /**
232
+ * GET request with query parameter support.
233
+ *
234
+ * @template T - Expected response data type
235
+ * @param url - Request URL
236
+ * @param params - Query parameters to append to URL
237
+ * @returns Promise resolving to typed response
238
+ *
239
+ * @example
240
+ * ```typescript
241
+ * const users = await client.get<User[]>('/api/users');
242
+ * const filteredUsers = await client.get<User[]>('/api/users', { status: 'active', limit: 10 });
243
+ * if (users.ok) console.log(users.data);
244
+ * ```
245
+ */
246
+ get<T>(url: string, params?: Record<string, string | number | boolean | undefined>): Promise<FetchResponse<T>>;
247
+ /**
248
+ * POST 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
+ * @example
257
+ * ```typescript
258
+ * const result = await client.post<User>('/api/users', { name: 'John' });
259
+ * ```
260
+ */
261
+ post<T>(url: string, body?: unknown, headers?: Record<string, string>): Promise<FetchResponse<T>>;
262
+ /**
263
+ * PUT request with automatic JSON serialization.
264
+ *
265
+ * @template T - Expected response data type
266
+ * @param url - Request URL
267
+ * @param body - Request body (auto-serialized to JSON)
268
+ * @param headers - Additional headers (Content-Type: application/json is default)
269
+ * @returns Promise resolving to typed response
270
+ */
271
+ put<T>(url: string, body?: unknown, headers?: Record<string, string>): Promise<FetchResponse<T>>;
272
+ /**
273
+ * PATCH request with automatic JSON serialization.
274
+ *
275
+ * @template T - Expected response data type
276
+ * @param url - Request URL
277
+ * @param body - Request body (auto-serialized to JSON)
278
+ * @param headers - Additional headers (Content-Type: application/json is default)
279
+ * @returns Promise resolving to typed response
280
+ */
281
+ patch<T>(url: string, body?: unknown, headers?: Record<string, string>): Promise<FetchResponse<T>>;
282
+ /**
283
+ * DELETE request with query parameter support.
284
+ *
285
+ * @template T - Expected response data type
286
+ * @param url - Request URL
287
+ * @param params - Query parameters to append to URL
288
+ * @returns Promise resolving to typed response
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * const result = await client.del('/api/users/123');
293
+ * const bulkResult = await client.del('/api/users', { status: 'inactive', force: true });
294
+ * if (result.ok) console.log('Deleted successfully');
295
+ * ```
296
+ */
297
+ del<T>(url: string, params?: Record<string, string | number | boolean | undefined>): Promise<FetchResponse<T>>;
298
+ }
299
+
300
+ /**
301
+ * @fileoverview Custom error classes - "Pit of Success" pattern.
302
+ *
303
+ * 🎯 LEVEL 1: HttpError, NetworkError - Most common error types you'll catch
304
+ * 🎯 LEVEL 2: FetchError - Base error class for advanced error handling
305
+ *
306
+ * @example
307
+ * ```typescript
308
+ * try {
309
+ * await client.get('/api/data');
310
+ * } catch (error) {
311
+ * if (error instanceof HttpError) {
312
+ * console.log(`HTTP ${error.status}: ${error.statusText}`);
313
+ * } else if (error instanceof NetworkError) {
314
+ * console.log('Network connection failed');
315
+ * }
316
+ * }
317
+ * ```
318
+ */
319
+ /**
320
+ * Base error class for all fetch client errors.
321
+ */
322
+ declare class FetchError extends Error {
323
+ /** Optional underlying cause */
324
+ readonly cause?: Error;
325
+ /**
326
+ * Creates a new FetchError.
327
+ * @param message - Error message
328
+ * @param cause - Optional underlying cause
329
+ */
330
+ constructor(message: string, cause?: Error);
331
+ }
332
+ /**
333
+ * Error thrown when an HTTP request fails with a non-2xx status code.
334
+ */
335
+ declare class HttpError extends FetchError {
336
+ /** The HTTP status code */
337
+ readonly status: number;
338
+ /** The HTTP status text */
339
+ readonly statusText: string;
340
+ /** The response body (if available) */
341
+ readonly body: unknown;
342
+ /**
343
+ * Creates a new HttpError.
344
+ * @param status - HTTP status code
345
+ * @param statusText - HTTP status text
346
+ * @param body - Response body
347
+ * @param url - The request URL
348
+ */
349
+ constructor(status: number, statusText: string, body: unknown, url: string);
350
+ }
351
+ /**
352
+ * Error thrown when a network request fails completely.
353
+ */
354
+ declare class NetworkError extends FetchError {
355
+ /**
356
+ * Creates a new NetworkError.
357
+ * @param message - Error message
358
+ * @param url - The request URL
359
+ * @param cause - The underlying network error
360
+ */
361
+ constructor(message: string, url: string, cause?: Error);
362
+ }
363
+
364
+ /**
365
+ * @fileoverview Authentication middleware types and configuration.
366
+ */
367
+ /**
368
+ * Authentication token provider function.
369
+ * Should return the current auth token or empty string if not available.
370
+ */
371
+ type AuthTokenProvider = () => string | Promise<string>;
372
+ /**
373
+ * Authentication configuration options - optimized for "pit of success".
374
+ *
375
+ * Smart defaults:
376
+ * - Uses standard Authorization header with Bearer token
377
+ * - Applies to all requests by default
378
+ * - Graceful handling when token is unavailable
379
+ */
380
+ interface AuthenticationOptions {
381
+ /**
382
+ * Function to get the current authentication token.
383
+ * Can be synchronous or asynchronous.
384
+ *
385
+ * @returns The auth token or empty string if not available
386
+ *
387
+ * @example Token from localStorage:
388
+ * ```typescript
389
+ * const getToken = () => localStorage.getItem('auth-token') || '';
390
+ * ```
391
+ *
392
+ * @example Async token refresh:
393
+ * ```typescript
394
+ * const getToken = async () => {
395
+ * const token = localStorage.getItem('auth-token');
396
+ * if (!token || isExpired(token)) {
397
+ * return await refreshToken();
398
+ * }
399
+ * return token;
400
+ * };
401
+ * ```
402
+ */
403
+ tokenProvider: AuthTokenProvider;
404
+ /**
405
+ * Header name for the authentication token (default: 'Authorization')
406
+ * The token will be prefixed with the tokenType
407
+ */
408
+ headerName?: string;
409
+ /**
410
+ * Token type prefix (default: 'Bearer')
411
+ * Common alternatives: 'Token', 'JWT', 'ApiKey'
412
+ */
413
+ tokenType?: string;
414
+ /**
415
+ * Skip authentication for requests matching these URL patterns
416
+ * Useful for public endpoints that don't need auth
417
+ *
418
+ * @example
419
+ * ```typescript
420
+ * skipPatterns: [/^\/public\//, '/health', '/login']
421
+ * ```
422
+ */
423
+ skipPatterns?: (RegExp | string)[];
424
+ /**
425
+ * Only apply authentication to requests matching these patterns
426
+ * If specified, only these patterns will get auth headers
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * includePatterns: [/^\/api\//, '/graphql']
431
+ * ```
432
+ */
433
+ includePatterns?: (RegExp | string)[];
434
+ }
435
+
436
+ /**
437
+ * @fileoverview Authentication middleware implementation.
438
+ */
439
+
440
+ /**
441
+ * Creates authentication middleware with smart defaults.
442
+ * Automatically adds Bearer tokens to requests.
443
+ *
444
+ * @param options - Authentication configuration options
445
+ * @returns Authentication middleware for use with FetchClient
446
+ *
447
+ * @example Basic usage:
448
+ * ```typescript
449
+ * const authClient = useAuthentication(client, {
450
+ * tokenProvider: () => localStorage.getItem('token') || ''
451
+ * });
452
+ * ```
453
+ *
454
+ * @example Async token provider:
455
+ * ```typescript
456
+ * const authClient = useAuthentication(client, {
457
+ * tokenProvider: async () => {
458
+ * const token = await getAuthToken();
459
+ * return token || '';
460
+ * }
461
+ * });
462
+ * ```
463
+ */
464
+ declare function createAuthenticationMiddleware(options: AuthenticationOptions): FetchMiddleware;
465
+
466
+ /**
467
+ * @fileoverview Authentication middleware - "pit of success" API.
468
+ */
469
+
470
+ /**
471
+ * "Pit of success" API for adding authentication to a FetchClient.
472
+ * Automatically adds Bearer tokens to requests.
473
+ *
474
+ * @param client - The FetchClient to add authentication to
475
+ * @param options - Authentication configuration
476
+ * @returns A new FetchClient with authentication middleware
477
+ *
478
+ * @example Basic token from localStorage:
479
+ * ```typescript
480
+ * const authClient = useAuthentication(client, {
481
+ * tokenProvider: () => localStorage.getItem('auth-token') || ''
482
+ * });
483
+ * ```
484
+ *
485
+ * @example Async token with refresh:
486
+ * ```typescript
487
+ * const authClient = useAuthentication(client, {
488
+ * tokenProvider: async () => {
489
+ * let token = localStorage.getItem('auth-token');
490
+ * if (!token || isExpired(token)) {
491
+ * token = await refreshToken();
492
+ * }
493
+ * return token || '';
494
+ * }
495
+ * });
496
+ * ```
497
+ */
498
+ declare function useAuthentication(client: FetchClient, options: AuthenticationOptions): FetchClient;
499
+
500
+ /**
501
+ * @fileoverview Authorization middleware types and configuration.
502
+ */
503
+
504
+ /**
505
+ * Handler function for unauthorized/forbidden responses.
506
+ */
507
+ type UnauthorizedHandler = (response: FetchResponse<unknown>, request: RequestInit & {
508
+ url?: string;
509
+ }) => void | Promise<void>;
510
+ /**
511
+ * Smart default configuration for redirect-based authorization handling.
512
+ */
513
+ interface RedirectAuthorizationConfig {
514
+ /**
515
+ * Path to redirect to on unauthorized response (default: '/login')
516
+ */
517
+ redirectPath?: string;
518
+ /**
519
+ * Query parameter name for the return URL (default: 'return_url')
520
+ */
521
+ returnUrlParam?: string;
522
+ /**
523
+ * Whether to include the current URL as a return URL (default: true)
524
+ * Set to false if you don't want the return URL functionality
525
+ */
526
+ includeReturnUrl?: boolean;
527
+ }
528
+ /**
529
+ * Authorization configuration options - optimized for "pit of success".
530
+ *
531
+ * Smart defaults:
532
+ * - Handles 401 Unauthorized responses
533
+ * - Optionally handles 403 Forbidden responses
534
+ * - Graceful error handling
535
+ * - When no options provided, defaults to redirecting to /login with return URL
536
+ */
537
+ interface AuthorizationOptions {
538
+ /**
539
+ * Handler called when 401 Unauthorized response is received.
540
+ *
541
+ * @param response - The 401 response object
542
+ * @param request - The original request that was unauthorized
543
+ *
544
+ * @example Redirect to login:
545
+ * ```typescript
546
+ * onUnauthorized: () => {
547
+ * window.location.href = '/login';
548
+ * }
549
+ * ```
550
+ *
551
+ * @example Clear token and reload:
552
+ * ```typescript
553
+ * onUnauthorized: () => {
554
+ * localStorage.removeItem('auth-token');
555
+ * window.location.reload();
556
+ * }
557
+ * ```
558
+ */
559
+ onUnauthorized?: UnauthorizedHandler;
560
+ /**
561
+ * Smart default configuration for redirect-based authorization.
562
+ * When provided, creates a default onUnauthorized handler that redirects
563
+ * to the login page with a return URL.
564
+ *
565
+ * @example Use defaults (redirects to '/login?return_url=current-page'):
566
+ * ```typescript
567
+ * redirectConfig: {}
568
+ * ```
569
+ *
570
+ * @example Custom redirect path:
571
+ * ```typescript
572
+ * redirectConfig: { redirectPath: '/signin' }
573
+ * ```
574
+ */
575
+ redirectConfig?: RedirectAuthorizationConfig;
576
+ /**
577
+ * Handler called when 403 Forbidden response is received.
578
+ * Optional - if not provided, 403 responses are ignored.
579
+ *
580
+ * @param response - The 403 response object
581
+ * @param request - The original request that was forbidden
582
+ */
583
+ onForbidden?: UnauthorizedHandler;
584
+ /**
585
+ * Skip authorization handling for requests matching these URL patterns
586
+ * Useful for login/public endpoints where 401 is expected
587
+ *
588
+ * @example
589
+ * ```typescript
590
+ * skipPatterns: ['/login', '/register', /^\/public\//]
591
+ * ```
592
+ */
593
+ skipPatterns?: (RegExp | string)[];
594
+ /**
595
+ * Status codes to handle (default: [401])
596
+ * You can add 403 if you want to handle forbidden responses
597
+ */
598
+ statusCodes?: number[];
599
+ }
600
+
601
+ /**
602
+ * @fileoverview Authorization middleware implementation.
603
+ */
604
+
605
+ /**
606
+ * Creates authorization middleware with smart defaults.
607
+ * Handles 401/403 responses by calling configured handlers.
608
+ *
609
+ * @param options - Authorization configuration options (optional)
610
+ * @returns Authorization middleware for use with FetchClient
611
+ *
612
+ * @example Smart defaults (no configuration needed):
613
+ * ```typescript
614
+ * const authzClient = useAuthorization(client);
615
+ * // Redirects to '/login?return_url=current-page' on 401
616
+ * ```
617
+ *
618
+ * @example Custom redirect configuration:
619
+ * ```typescript
620
+ * const authzClient = useAuthorization(client, {
621
+ * redirectConfig: {
622
+ * redirectPath: '/signin',
623
+ * returnUrlParam: 'redirect_to'
624
+ * }
625
+ * });
626
+ * ```
627
+ *
628
+ * @example Manual handler (full control):
629
+ * ```typescript
630
+ * const authzClient = useAuthorization(client, {
631
+ * onUnauthorized: () => window.location.href = '/login'
632
+ * });
633
+ * ```
634
+ *
635
+ * @example Handle both 401 and 403:
636
+ * ```typescript
637
+ * const authzClient = useAuthorization(client, {
638
+ * onForbidden: () => showAccessDeniedMessage(),
639
+ * statusCodes: [401, 403]
640
+ * });
641
+ * ```
642
+ */
643
+ declare function createAuthorizationMiddleware(options?: AuthorizationOptions): FetchMiddleware;
644
+
645
+ /**
646
+ * @fileoverview Authorization middleware - "pit of success" API.
647
+ */
648
+
649
+ /**
650
+ * "Pit of success" API for adding authorization handling to a FetchClient.
651
+ * Automatically handles 401 Unauthorized responses.
652
+ *
653
+ * @param client - The FetchClient to add authorization handling to
654
+ * @param options - Authorization configuration (optional)
655
+ * @returns A new FetchClient with authorization middleware
656
+ *
657
+ * @example Smart defaults - no configuration needed:
658
+ * ```typescript
659
+ * const authzClient = useAuthorization(client);
660
+ * // Redirects to '/login?return_url=current-page' on 401
661
+ * ```
662
+ *
663
+ * @example Custom redirect path:
664
+ * ```typescript
665
+ * const authzClient = useAuthorization(client, {
666
+ * redirectConfig: { redirectPath: '/signin', returnUrlParam: 'redirect_to' }
667
+ * });
668
+ * ```
669
+ *
670
+ * @example Manual handler (full control):
671
+ * ```typescript
672
+ * const authzClient = useAuthorization(client, {
673
+ * onUnauthorized: () => {
674
+ * localStorage.removeItem('auth-token');
675
+ * window.location.href = '/login';
676
+ * }
677
+ * });
678
+ * ```
679
+ *
680
+ * @example Handle multiple status codes:
681
+ * ```typescript
682
+ * const authzClient = useAuthorization(client, {
683
+ * onForbidden: () => showAccessDenied(),
684
+ * statusCodes: [401, 403]
685
+ * });
686
+ * ```
687
+ */
688
+ declare function useAuthorization(client: FetchClient, options?: AuthorizationOptions): FetchClient;
689
+
690
+ /**
691
+ * @fileoverview Cache middleware types and configuration.
692
+ */
693
+ /**
694
+ * Cache key generator function.
695
+ * Should return a unique key for the request.
696
+ */
697
+ type CacheKeyGenerator = (request: RequestInit & {
698
+ url?: string;
699
+ }) => string;
700
+ /**
701
+ * Cache storage interface.
702
+ * Allows custom cache implementations.
703
+ */
704
+ interface CacheStorage {
705
+ get(key: string): Promise<CacheEntry | null>;
706
+ getWithExpiry?(key: string): Promise<{
707
+ entry: CacheEntry | null;
708
+ isExpired: boolean;
709
+ }>;
710
+ set(key: string, entry: CacheEntry): Promise<void>;
711
+ delete(key: string): Promise<void>;
712
+ clear(): Promise<void>;
713
+ }
714
+ /**
715
+ * Cached response entry.
716
+ */
717
+ interface CacheEntry {
718
+ response: {
719
+ status: number;
720
+ statusText: string;
721
+ headers: Record<string, string>;
722
+ data: unknown;
723
+ };
724
+ timestamp: number;
725
+ expiresAt: number;
726
+ }
727
+ /**
728
+ * Cache configuration options - optimized for "pit of success".
729
+ *
730
+ * Smart defaults:
731
+ * - Only caches GET requests
732
+ * - 5 minute default TTL
733
+ * - Memory-based storage
734
+ * - Automatic cache key generation
735
+ */
736
+ interface CacheOptions {
737
+ /**
738
+ * Time to live in milliseconds (default: 300000 = 5 minutes)
739
+ * How long responses should be cached
740
+ */
741
+ ttl?: number;
742
+ /**
743
+ * HTTP methods to cache (default: ['GET'])
744
+ * Only these methods will be cached
745
+ */
746
+ methods?: string[];
747
+ /**
748
+ * Cache storage implementation (default: in-memory)
749
+ * Can be replaced with localStorage, IndexedDB, etc.
750
+ */
751
+ storage?: CacheStorage;
752
+ /**
753
+ * Custom cache key generator (default: URL + method + headers)
754
+ * Should return a unique key for each request
755
+ *
756
+ * @example Custom key generator:
757
+ * ```typescript
758
+ * keyGenerator: (request) => `${request.method}:${request.url}`
759
+ * ```
760
+ */
761
+ keyGenerator?: CacheKeyGenerator;
762
+ /**
763
+ * Skip caching for requests matching these URL patterns
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * skipPatterns: [/\/api\/user/, '/dynamic-data']
768
+ * ```
769
+ */
770
+ skipPatterns?: (RegExp | string)[];
771
+ /**
772
+ * Whether to serve stale cache entries while revalidating
773
+ * When true, returns cached data immediately and updates cache in background
774
+ */
775
+ staleWhileRevalidate?: boolean;
776
+ }
777
+
778
+ /**
779
+ * @fileoverview Cache middleware implementation.
780
+ */
781
+
782
+ /**
783
+ * Creates cache middleware with smart defaults.
784
+ * Caches GET responses for faster subsequent requests.
785
+ *
786
+ * @param options - Cache configuration options
787
+ * @returns Cache middleware for use with FetchClient
788
+ *
789
+ * @example Basic caching:
790
+ * ```typescript
791
+ * const cachedClient = useCache(client);
792
+ * // GET requests will be cached for 5 minutes
793
+ * ```
794
+ *
795
+ * @example Custom TTL:
796
+ * ```typescript
797
+ * const cachedClient = useCache(client, {
798
+ * ttl: 10 * 60 * 1000 // 10 minutes
799
+ * });
800
+ * ```
801
+ */
802
+ declare function createCacheMiddleware(options?: CacheOptions): FetchMiddleware;
803
+
804
+ /**
805
+ * @fileoverview Cache middleware - "pit of success" API.
806
+ */
807
+
808
+ /**
809
+ * "Pit of success" API for adding response caching to a FetchClient.
810
+ * Caches GET responses for faster subsequent requests.
811
+ *
812
+ * @param client - The FetchClient to add caching to
813
+ * @param options - Cache configuration options
814
+ * @returns A new FetchClient with cache middleware
815
+ *
816
+ * @example Basic caching (5 minute TTL):
817
+ * ```typescript
818
+ * const cachedClient = useCache(client);
819
+ *
820
+ * // First call hits the network
821
+ * await cachedClient.get('/api/data');
822
+ *
823
+ * // Second call returns cached data
824
+ * await cachedClient.get('/api/data');
825
+ * ```
826
+ *
827
+ * @example Custom TTL and methods:
828
+ * ```typescript
829
+ * const cachedClient = useCache(client, {
830
+ * ttl: 10 * 60 * 1000, // 10 minutes
831
+ * methods: ['GET', 'HEAD']
832
+ * });
833
+ * ```
834
+ *
835
+ * @example Stale-while-revalidate:
836
+ * ```typescript
837
+ * const cachedClient = useCache(client, {
838
+ * staleWhileRevalidate: true
839
+ * });
840
+ * // Returns stale data immediately, updates cache in background
841
+ * ```
842
+ */
843
+ declare function useCache(client: FetchClient, options?: CacheOptions): FetchClient;
844
+
845
+ /**
846
+ * @fileoverview CSRF protection middleware types and configuration.
847
+ */
848
+ /**
849
+ * CSRF token provider function.
850
+ * Should return the current CSRF token or empty string if not available.
851
+ */
852
+ type CSRFTokenProvider = () => string;
853
+ /**
854
+ * CSRF configuration options - optimized for "pit of success".
855
+ *
856
+ * Smart defaults:
857
+ * - Uses standard X-XSRF-TOKEN header
858
+ * - Automatically extracts token from XSRF-TOKEN cookie
859
+ * - Only adds token to state-changing methods (POST, PUT, PATCH, DELETE)
860
+ */
861
+ interface CSRFOptions {
862
+ /**
863
+ * Function to get the current CSRF token.
864
+ * Default: extracts from XSRF-TOKEN cookie (standard Rails/Laravel convention)
865
+ *
866
+ * @returns The CSRF token or empty string if not available
867
+ *
868
+ * @example Custom token provider:
869
+ * ```typescript
870
+ * const getToken = () => localStorage.getItem('csrf-token') || '';
871
+ * ```
872
+ */
873
+ tokenProvider?: CSRFTokenProvider;
874
+ /**
875
+ * Header name to use for CSRF token (default: 'X-XSRF-TOKEN')
876
+ * Common alternatives: 'X-CSRF-Token', 'X-CSRFToken'
877
+ */
878
+ headerName?: string;
879
+ /**
880
+ * Cookie name to read token from when using default provider (default: 'XSRF-TOKEN')
881
+ * Common alternatives: 'csrf-token', '_token'
882
+ */
883
+ cookieName?: string;
884
+ /**
885
+ * HTTP methods that require CSRF protection (default: ['POST', 'PUT', 'PATCH', 'DELETE'])
886
+ * GET and HEAD requests typically don't need CSRF tokens
887
+ */
888
+ protectedMethods?: string[];
889
+ /**
890
+ * Skip CSRF protection for requests matching these URL patterns
891
+ * Useful for external API calls that don't need CSRF tokens
892
+ *
893
+ * @example
894
+ * ```typescript
895
+ * skipPatterns: [/^https:\/\/api\.external\.com\//, '/public-api/']
896
+ * ```
897
+ */
898
+ skipPatterns?: (RegExp | string)[];
899
+ }
900
+
901
+ /**
902
+ * @fileoverview CSRF protection middleware - "pit of success" API.
903
+ */
904
+
905
+ /**
906
+ * "Pit of success" API for adding CSRF protection to a FetchClient.
907
+ * Uses smart defaults that work with most web frameworks out of the box.
908
+ *
909
+ * Default behavior:
910
+ * - Reads CSRF token from XSRF-TOKEN cookie
911
+ * - Adds X-XSRF-TOKEN header to POST, PUT, PATCH, DELETE requests
912
+ * - Skips GET/HEAD requests (they don't need CSRF protection)
913
+ *
914
+ * @param client - The FetchClient to add CSRF protection to
915
+ * @param options - Optional CSRF configuration
916
+ * @returns A new FetchClient with CSRF protection
917
+ *
918
+ * @example Basic usage (automatic cookie-based CSRF):
919
+ * ```typescript
920
+ * const client = new FetchClient();
921
+ * const protectedClient = useCSRF(client);
922
+ *
923
+ * // CSRF token automatically added to POST requests
924
+ * await protectedClient.post('/api/users', { name: 'John' });
925
+ * ```
926
+ *
927
+ * @example Custom token provider:
928
+ * ```typescript
929
+ * const protectedClient = useCSRF(client, {
930
+ * tokenProvider: () => localStorage.getItem('csrf-token') || ''
931
+ * });
932
+ * ```
933
+ *
934
+ * @example Custom header and cookie names:
935
+ * ```typescript
936
+ * const protectedClient = useCSRF(client, {
937
+ * headerName: 'X-CSRF-Token',
938
+ * cookieName: 'csrf-token'
939
+ * });
940
+ * ```
941
+ *
942
+ * @example Skip patterns for external APIs:
943
+ * ```typescript
944
+ * const protectedClient = useCSRF(client, {
945
+ * skipPatterns: [
946
+ * /^https:\/\/api\.external\.com\//, // Skip external API
947
+ * '/webhook/', // Skip webhook endpoints
948
+ * '/public-api/' // Skip public API endpoints
949
+ * ]
950
+ * });
951
+ * ```
952
+ */
953
+ declare function useCSRF(client: FetchClient, options?: CSRFOptions): FetchClient;
954
+
955
+ /**
956
+ * @fileoverview Logging middleware types and configuration.
957
+ */
958
+ /**
959
+ * Log levels for filtering log output.
960
+ */
961
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
962
+ /**
963
+ * Log entry structure.
964
+ */
965
+ interface LogEntry {
966
+ level: LogLevel;
967
+ timestamp: number;
968
+ method: string;
969
+ url: string;
970
+ status?: number;
971
+ duration?: number;
972
+ error?: Error;
973
+ requestHeaders?: Record<string, string>;
974
+ responseHeaders?: Record<string, string>;
975
+ requestBody?: unknown;
976
+ responseBody?: unknown;
977
+ }
978
+ /**
979
+ * Custom logger interface.
980
+ */
981
+ interface Logger {
982
+ debug(message: string, data?: unknown): void;
983
+ info(message: string, data?: unknown): void;
984
+ warn(message: string, data?: unknown): void;
985
+ error(message: string, data?: unknown): void;
986
+ }
987
+ /**
988
+ * Logging configuration options - optimized for "pit of success".
989
+ *
990
+ * Smart defaults:
991
+ * - Logs to console
992
+ * - Info level by default
993
+ * - Excludes request/response bodies by default
994
+ * - Includes timing information
995
+ */
996
+ interface LoggingOptions {
997
+ /**
998
+ * Minimum log level to output (default: 'info')
999
+ * Logs at this level and above will be output
1000
+ */
1001
+ level?: LogLevel;
1002
+ /**
1003
+ * Custom logger implementation (default: console)
1004
+ * Can be replaced with winston, pino, etc.
1005
+ */
1006
+ logger?: Logger;
1007
+ /**
1008
+ * Include request headers in logs (default: false)
1009
+ * May contain sensitive information
1010
+ */
1011
+ includeRequestHeaders?: boolean;
1012
+ /**
1013
+ * Include response headers in logs (default: false)
1014
+ * May contain sensitive information
1015
+ */
1016
+ includeResponseHeaders?: boolean;
1017
+ /**
1018
+ * Include request body in logs (default: false)
1019
+ * May contain sensitive information and increase log size
1020
+ */
1021
+ includeRequestBody?: boolean;
1022
+ /**
1023
+ * Include response body in logs (default: false)
1024
+ * May contain sensitive information and increase log size
1025
+ */
1026
+ includeResponseBody?: boolean;
1027
+ /**
1028
+ * Skip logging for requests matching these URL patterns
1029
+ * Useful for health checks, metrics endpoints, etc.
1030
+ *
1031
+ * @example
1032
+ * ```typescript
1033
+ * skipPatterns: ['/health', '/metrics', /\/static\//]
1034
+ * ```
1035
+ */
1036
+ skipPatterns?: (RegExp | string)[];
1037
+ /**
1038
+ * Custom log formatter function
1039
+ * Allows complete customization of log output
1040
+ */
1041
+ formatter?: (entry: LogEntry) => string;
1042
+ }
1043
+
1044
+ /**
1045
+ * @fileoverview Logging middleware implementation.
1046
+ */
1047
+
1048
+ /**
1049
+ * Creates logging middleware with smart defaults.
1050
+ * Logs HTTP requests and responses for debugging and monitoring.
1051
+ *
1052
+ * @param options - Logging configuration options
1053
+ * @returns Logging middleware for use with FetchClient
1054
+ *
1055
+ * @example Basic logging:
1056
+ * ```typescript
1057
+ * const loggedClient = useLogging(client);
1058
+ * // Logs all requests to console
1059
+ * ```
1060
+ *
1061
+ * @example Custom logger:
1062
+ * ```typescript
1063
+ * const loggedClient = useLogging(client, {
1064
+ * logger: winston.createLogger({...}),
1065
+ * level: 'debug',
1066
+ * includeRequestHeaders: true
1067
+ * });
1068
+ * ```
1069
+ */
1070
+ declare function createLoggingMiddleware(options?: LoggingOptions): FetchMiddleware;
1071
+
1072
+ /**
1073
+ * @fileoverview Logging middleware - "pit of success" API.
1074
+ */
1075
+
1076
+ /**
1077
+ * "Pit of success" API for adding logging to a FetchClient.
1078
+ * Logs HTTP requests and responses for debugging and monitoring.
1079
+ *
1080
+ * @param client - The FetchClient to add logging to
1081
+ * @param options - Logging configuration options
1082
+ * @returns A new FetchClient with logging middleware
1083
+ *
1084
+ * @example Basic logging to console:
1085
+ * ```typescript
1086
+ * const loggedClient = useLogging(client);
1087
+ *
1088
+ * // Logs: → GET /api/users
1089
+ * // Logs: ← GET /api/users → 200 (245ms)
1090
+ * await loggedClient.get('/api/users');
1091
+ * ```
1092
+ *
1093
+ * @example Custom log level and headers:
1094
+ * ```typescript
1095
+ * const loggedClient = useLogging(client, {
1096
+ * level: 'debug',
1097
+ * includeRequestHeaders: true,
1098
+ * includeResponseHeaders: true
1099
+ * });
1100
+ * ```
1101
+ *
1102
+ * @example Skip health check endpoints:
1103
+ * ```typescript
1104
+ * const loggedClient = useLogging(client, {
1105
+ * skipPatterns: ['/health', '/metrics', '/ping']
1106
+ * });
1107
+ * ```
1108
+ */
1109
+ declare function useLogging(client: FetchClient, options?: LoggingOptions): FetchClient;
1110
+
1111
+ /**
1112
+ * @fileoverview Rate limiting middleware types and configuration.
1113
+ */
1114
+ /**
1115
+ * Rate limiting algorithm types.
1116
+ */
1117
+ type RateLimitAlgorithm = 'token-bucket' | 'sliding-window' | 'fixed-window';
1118
+ /**
1119
+ * Rate limiting configuration options - optimized for "pit of success".
1120
+ *
1121
+ * Smart defaults:
1122
+ * - 60 requests per minute
1123
+ * - Token bucket algorithm
1124
+ * - Per-client limiting
1125
+ * - Graceful handling when rate limit exceeded
1126
+ */
1127
+ interface RateLimitOptions {
1128
+ /**
1129
+ * Maximum number of requests allowed (default: 60)
1130
+ */
1131
+ maxRequests?: number;
1132
+ /**
1133
+ * Time window in milliseconds (default: 60000 = 1 minute)
1134
+ */
1135
+ windowMs?: number;
1136
+ /**
1137
+ * Rate limiting algorithm (default: 'token-bucket')
1138
+ * - 'token-bucket': Allows bursts up to maxRequests, refills over time
1139
+ * - 'sliding-window': Smooth rate limiting over rolling window
1140
+ * - 'fixed-window': Fixed number of requests per fixed time window
1141
+ */
1142
+ algorithm?: RateLimitAlgorithm;
1143
+ /**
1144
+ * Custom key generator for rate limiting scope
1145
+ * Default: single global rate limit for all requests
1146
+ *
1147
+ * @example Per-endpoint rate limiting:
1148
+ * ```typescript
1149
+ * keyGenerator: (request) => request.url || 'default'
1150
+ * ```
1151
+ *
1152
+ * @example Per-user rate limiting:
1153
+ * ```typescript
1154
+ * keyGenerator: (request) => {
1155
+ * const auth = request.headers?.get('Authorization');
1156
+ * return auth ? `user:${auth}` : 'anonymous';
1157
+ * }
1158
+ * ```
1159
+ */
1160
+ keyGenerator?: (request: RequestInit & {
1161
+ url?: string;
1162
+ }) => string;
1163
+ /**
1164
+ * Skip rate limiting for requests matching these URL patterns
1165
+ *
1166
+ * @example
1167
+ * ```typescript
1168
+ * skipPatterns: ['/health', /^\/public\//]
1169
+ * ```
1170
+ */
1171
+ skipPatterns?: (RegExp | string)[];
1172
+ /**
1173
+ * Custom handler called when rate limit is exceeded
1174
+ * Can return a custom response or void to use default behavior
1175
+ *
1176
+ * @param retryAfter - Milliseconds until next request is allowed
1177
+ * @param request - The rate-limited request
1178
+ * @returns Custom response or void for default behavior
1179
+ */
1180
+ onRateLimitExceeded?: (retryAfter: number, request: RequestInit & {
1181
+ url?: string;
1182
+ }) => void | Promise<void> | {
1183
+ data: unknown;
1184
+ status: number;
1185
+ statusText: string;
1186
+ headers: Headers;
1187
+ url: string;
1188
+ ok: boolean;
1189
+ error?: {
1190
+ message: string;
1191
+ body?: unknown;
1192
+ };
1193
+ } | Promise<{
1194
+ data: unknown;
1195
+ status: number;
1196
+ statusText: string;
1197
+ headers: Headers;
1198
+ url: string;
1199
+ ok: boolean;
1200
+ error?: {
1201
+ message: string;
1202
+ body?: unknown;
1203
+ };
1204
+ }>;
1205
+ }
1206
+
1207
+ /**
1208
+ * @fileoverview Rate limiting middleware implementation.
1209
+ */
1210
+
1211
+ /**
1212
+ * Creates rate limiting middleware - mainly for API quota management.
1213
+ * Note: Rate limiting is typically a server concern, but this can help with:
1214
+ * - Respecting API provider limits
1215
+ * - Preventing runaway requests in bulk operations
1216
+ * - Cost management for pay-per-request APIs
1217
+ */
1218
+ declare function createRateLimitMiddleware(options?: RateLimitOptions): FetchMiddleware;
1219
+
1220
+ /**
1221
+ * @fileoverview Rate limiting middleware - specialized use cases.
1222
+ */
1223
+
1224
+ /**
1225
+ * Rate limiting middleware - mainly for API quota management.
1226
+ * Note: This is primarily useful for specific scenarios like:
1227
+ * - Respecting third-party API limits
1228
+ * - Bulk operations that need throttling
1229
+ * - Pay-per-request API cost management
1230
+ */
1231
+ declare function useRateLimit(client: FetchClient, options?: RateLimitOptions): FetchClient;
1232
+
1233
+ /**
1234
+ * @fileoverview Retry middleware types and configuration.
1235
+ */
1236
+ /**
1237
+ * Retry configuration options - optimized for "pit of success".
1238
+ *
1239
+ * Smart defaults:
1240
+ * - 3 retries (4 total attempts)
1241
+ * - Exponential backoff starting at 1000ms
1242
+ * - Only retry on network errors and 5xx status codes
1243
+ */
1244
+ interface RetryOptions {
1245
+ /**
1246
+ * Maximum number of retry attempts (default: 3)
1247
+ * Total attempts will be maxRetries + 1
1248
+ */
1249
+ maxRetries?: number;
1250
+ /**
1251
+ * Initial delay in milliseconds (default: 1000)
1252
+ * Subsequent delays use exponential backoff
1253
+ */
1254
+ delay?: number;
1255
+ /**
1256
+ * Backoff strategy (default: 'exponential')
1257
+ * - 'exponential': delay * (2 ^ attempt)
1258
+ * - 'linear': delay * attempt
1259
+ * - 'fixed': always use delay
1260
+ */
1261
+ backoff?: 'exponential' | 'linear' | 'fixed';
1262
+ /**
1263
+ * Maximum delay cap in milliseconds (default: 30000 = 30s)
1264
+ * Prevents exponential backoff from getting too large
1265
+ */
1266
+ maxDelay?: number;
1267
+ /**
1268
+ * Custom function to determine if a response should be retried
1269
+ * Default: retry on network errors (status 0) and server errors (5xx)
1270
+ *
1271
+ * @param response - The fetch response or error
1272
+ * @param attempt - Current attempt number (1-based)
1273
+ * @returns true if request should be retried
1274
+ */
1275
+ shouldRetry?: (response: {
1276
+ status: number;
1277
+ ok: boolean;
1278
+ }, attempt: number) => boolean;
1279
+ /**
1280
+ * Optional callback called before each retry attempt
1281
+ * Useful for logging or analytics
1282
+ *
1283
+ * @param attempt - Current attempt number (1-based)
1284
+ * @param delay - Delay before this retry in ms
1285
+ * @param lastResponse - The failed response that triggered the retry
1286
+ */
1287
+ onRetry?: (attempt: number, delay: number, lastResponse: {
1288
+ status: number;
1289
+ statusText: string;
1290
+ }) => void;
1291
+ }
1292
+
1293
+ /**
1294
+ * @fileoverview Retry middleware implementation with enhanced architecture.
1295
+ */
1296
+
1297
+ /**
1298
+ * Creates a retry middleware with smart defaults.
1299
+ *
1300
+ * 🎯 PIT OF SUCCESS: Works great with no config, customizable when needed.
1301
+ *
1302
+ * Features:
1303
+ * - ✅ Preserves full middleware chain on retries (unlike old implementation)
1304
+ * - ✅ Exponential backoff with jitter
1305
+ * - ✅ Smart retry conditions (network errors + 5xx)
1306
+ * - ✅ Configurable but sensible defaults
1307
+ * - ✅ Type-safe configuration
1308
+ *
1309
+ * @param options - Retry configuration (all optional)
1310
+ * @returns Middleware function
1311
+ *
1312
+ * @example Basic usage:
1313
+ * ```typescript
1314
+ * const client = new FetchClient();
1315
+ * client.use(createRetryMiddleware()); // 3 retries with exponential backoff
1316
+ * ```
1317
+ *
1318
+ * @example Custom configuration:
1319
+ * ```typescript
1320
+ * const client = new FetchClient();
1321
+ * client.use(createRetryMiddleware({
1322
+ * maxRetries: 5,
1323
+ * delay: 500,
1324
+ * backoff: 'linear',
1325
+ * onRetry: (attempt, delay) => console.log(`Retry ${attempt} in ${delay}ms`)
1326
+ * }));
1327
+ * ```
1328
+ */
1329
+ declare function createRetryMiddleware(options?: RetryOptions): FetchMiddleware;
1330
+
1331
+ declare function useRetry(client: FetchClient, options?: RetryOptions): FetchClient;
1332
+
1333
+ /**
1334
+ * @fileoverview Complete middleware collection for FetchClient - "pit of success" APIs.
1335
+ *
1336
+ * This module provides a comprehensive set of middleware for common HTTP client concerns:
1337
+ * - 🔐 Authentication: Bearer token injection
1338
+ * - 🛡️ Authorization: 401/403 response handling
1339
+ * - 💾 Cache: Response caching with TTL
1340
+ * - 🔒 CSRF: Cross-site request forgery protection
1341
+ * - 📝 Logging: Request/response logging
1342
+ * - 🚦 Rate Limiting: Request rate limiting with token bucket
1343
+ * - 🔄 Retry: Automatic retry with backoff
1344
+ *
1345
+ * Each middleware follows the "pit of success" pattern with:
1346
+ * - Smart defaults for common scenarios
1347
+ * - Simple `use{Middleware}()` convenience functions
1348
+ * - Advanced `create{Middleware}Middleware()` for custom scenarios
1349
+ * - Comprehensive TypeScript support
1350
+ *
1351
+ * @example Quick setup with multiple middleware:
1352
+ * ```typescript
1353
+ * import { FetchClient } from '@fgrzl/fetch';
1354
+ * import { useAuthentication, useRetry, useLogging } from '@fgrzl/fetch/middleware';
1355
+ *
1356
+ * const client = new FetchClient();
1357
+ * const enhancedClient = useAuthentication(client, {
1358
+ * tokenProvider: () => localStorage.getItem('auth-token') || ''
1359
+ * })
1360
+ * .pipe(useRetry, { retries: 3 })
1361
+ * .pipe(useLogging);
1362
+ * ```
1363
+ */
1364
+
1365
+ /**
1366
+ * Production-ready middleware stack with authentication, retry, logging, and caching.
1367
+ * Perfect for API clients that need reliability and observability.
1368
+ *
1369
+ * @param client - The FetchClient to enhance
1370
+ * @param config - Configuration for each middleware
1371
+ * @returns Enhanced FetchClient with production middleware stack
1372
+ *
1373
+ * @example
1374
+ * ```typescript
1375
+ * const apiClient = useProductionStack(new FetchClient(), {
1376
+ * auth: { tokenProvider: () => getAuthToken() },
1377
+ * cache: { ttl: 5 * 60 * 1000 }, // 5 minutes
1378
+ * logging: { level: 'info' }
1379
+ * });
1380
+ * ```
1381
+ */
1382
+ declare function useProductionStack(client: FetchClient, config?: {
1383
+ auth?: Parameters<typeof useAuthentication>[1];
1384
+ retry?: Parameters<typeof useRetry>[1];
1385
+ cache?: Parameters<typeof useCache>[1];
1386
+ logging?: Parameters<typeof useLogging>[1];
1387
+ rateLimit?: Parameters<typeof useRateLimit>[1];
1388
+ }): FetchClient;
1389
+ /**
1390
+ * Development-friendly middleware stack with comprehensive logging and retries.
1391
+ * Perfect for local development and debugging.
1392
+ *
1393
+ * @param client - The FetchClient to enhance
1394
+ * @param config - Configuration for development middleware
1395
+ * @returns Enhanced FetchClient with development middleware stack
1396
+ *
1397
+ * @example
1398
+ * ```typescript
1399
+ * const devClient = useDevelopmentStack(new FetchClient(), {
1400
+ * auth: { tokenProvider: () => 'dev-token' }
1401
+ * });
1402
+ * ```
1403
+ */
1404
+ declare function useDevelopmentStack(client: FetchClient, config?: {
1405
+ auth?: Parameters<typeof useAuthentication>[1];
1406
+ }): FetchClient;
1407
+ /**
1408
+ * Basic middleware stack with just authentication and retry.
1409
+ * Perfect for simple API clients that need minimal overhead.
1410
+ *
1411
+ * @param client - The FetchClient to enhance
1412
+ * @param config - Basic configuration
1413
+ * @returns Enhanced FetchClient with basic middleware stack
1414
+ *
1415
+ * @example
1416
+ * ```typescript
1417
+ * const basicClient = useBasicStack(new FetchClient(), {
1418
+ * auth: { tokenProvider: () => getToken() }
1419
+ * });
1420
+ * ```
1421
+ */
1422
+ declare function useBasicStack(client: FetchClient, config: {
1423
+ auth: Parameters<typeof useAuthentication>[1];
1424
+ }): FetchClient;
1425
+
1
1426
  /**
2
1427
  * @fileoverview Main library entry point with "pit of success" architecture.
3
1428
  *
@@ -8,7 +1433,7 @@
8
1433
  * 4. Pre-built middleware stacks for common scenarios
9
1434
  * 5. Types for TypeScript users
10
1435
  */
11
- import { FetchClient } from './client/fetch-client';
1436
+
12
1437
  /**
13
1438
  * 🎯 PIT OF SUCCESS: Pre-configured fetch client (Level 1 - 80% of users)
14
1439
  *
@@ -54,12 +1479,5 @@ import { FetchClient } from './client/fetch-client';
54
1479
  * ```
55
1480
  */
56
1481
  declare const api: FetchClient;
57
- export default api;
58
- export { FetchClient } from './client/fetch-client';
59
- export { FetchError, HttpError, NetworkError } from './errors';
60
- export { useAuthentication, createAuthenticationMiddleware, useAuthorization, createAuthorizationMiddleware, useCache, createCacheMiddleware, useCSRF, useLogging, createLoggingMiddleware, useRateLimit, createRateLimitMiddleware, useRetry, createRetryMiddleware, } from './middleware';
61
- export { useProductionStack, useDevelopmentStack, useBasicStack, } from './middleware';
62
- export type { FetchMiddleware as InterceptMiddleware } from './client/fetch-client';
63
- export type { FetchResponse, FetchClientOptions } from './client/types';
64
- export type { AuthenticationOptions, AuthTokenProvider, AuthorizationOptions, UnauthorizedHandler, CacheOptions, CacheStorage, CacheEntry, CacheKeyGenerator, LoggingOptions, Logger, LogLevel, RateLimitOptions, RateLimitAlgorithm, RetryOptions, } from './middleware';
65
- //# sourceMappingURL=index.d.ts.map
1482
+
1483
+ export { type AuthTokenProvider, type AuthenticationOptions, type AuthorizationOptions, type CacheEntry, type CacheKeyGenerator, type CacheOptions, type CacheStorage, FetchClient, type FetchClientOptions, FetchError, type FetchResponse, HttpError, type FetchMiddleware as InterceptMiddleware, type LogLevel, type Logger, type LoggingOptions, NetworkError, type RateLimitAlgorithm, type RateLimitOptions, type RetryOptions, type UnauthorizedHandler, createAuthenticationMiddleware, createAuthorizationMiddleware, createCacheMiddleware, createLoggingMiddleware, createRateLimitMiddleware, createRetryMiddleware, api as default, useAuthentication, useAuthorization, useBasicStack, useCSRF, useCache, useDevelopmentStack, useLogging, useProductionStack, useRateLimit, useRetry };