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