@fgrzl/fetch 1.1.0-alpha.3 → 1.1.0-alpha.8

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 (231) hide show
  1. package/README.md +15 -12
  2. package/dist/cjs/client/fetch-client.d.ts +189 -0
  3. package/dist/cjs/client/fetch-client.d.ts.map +1 -0
  4. package/dist/cjs/client/fetch-client.js +339 -0
  5. package/dist/cjs/client/fetch-client.js.map +1 -0
  6. package/dist/cjs/client/index.d.ts +11 -0
  7. package/dist/cjs/client/index.d.ts.map +1 -0
  8. package/dist/cjs/client/index.js +14 -0
  9. package/dist/cjs/client/index.js.map +1 -0
  10. package/dist/cjs/client/types.d.ts +63 -0
  11. package/dist/cjs/client/types.d.ts.map +1 -0
  12. package/dist/cjs/client/types.js +9 -0
  13. package/dist/cjs/client/types.js.map +1 -0
  14. package/dist/{errors.d.ts → cjs/errors/index.d.ts} +20 -3
  15. package/dist/cjs/errors/index.d.ts.map +1 -0
  16. package/dist/{errors.js → cjs/errors/index.js} +23 -3
  17. package/dist/cjs/errors/index.js.map +1 -0
  18. package/dist/cjs/index.d.ts +65 -0
  19. package/dist/cjs/index.d.ts.map +1 -0
  20. package/dist/cjs/index.js +118 -0
  21. package/dist/cjs/index.js.map +1 -0
  22. package/dist/cjs/middleware/authentication/authentication.d.ts +31 -0
  23. package/dist/cjs/middleware/authentication/authentication.d.ts.map +1 -0
  24. package/dist/cjs/middleware/authentication/authentication.js +93 -0
  25. package/dist/cjs/middleware/authentication/authentication.js.map +1 -0
  26. package/dist/cjs/middleware/authentication/index.d.ts +37 -0
  27. package/dist/cjs/middleware/authentication/index.d.ts.map +1 -0
  28. package/dist/cjs/middleware/authentication/index.js +42 -0
  29. package/dist/cjs/middleware/authentication/index.js.map +1 -0
  30. package/dist/cjs/middleware/authentication/types.d.ts +73 -0
  31. package/dist/cjs/middleware/authentication/types.d.ts.map +1 -0
  32. package/dist/cjs/middleware/authentication/types.js +6 -0
  33. package/dist/cjs/middleware/authentication/types.js.map +1 -0
  34. package/dist/cjs/middleware/authorization/authorization.d.ts +30 -0
  35. package/dist/cjs/middleware/authorization/authorization.d.ts.map +1 -0
  36. package/dist/cjs/middleware/authorization/authorization.js +82 -0
  37. package/dist/cjs/middleware/authorization/authorization.js.map +1 -0
  38. package/dist/cjs/middleware/authorization/index.d.ts +36 -0
  39. package/dist/cjs/middleware/authorization/index.d.ts.map +1 -0
  40. package/dist/cjs/middleware/authorization/index.js +41 -0
  41. package/dist/cjs/middleware/authorization/index.js.map +1 -0
  42. package/dist/cjs/middleware/authorization/types.d.ts +67 -0
  43. package/dist/cjs/middleware/authorization/types.d.ts.map +1 -0
  44. package/dist/cjs/middleware/authorization/types.js +6 -0
  45. package/dist/cjs/middleware/authorization/types.js.map +1 -0
  46. package/dist/cjs/middleware/cache/cache.d.ts +41 -0
  47. package/dist/cjs/middleware/cache/cache.d.ts.map +1 -0
  48. package/dist/cjs/middleware/cache/cache.js +191 -0
  49. package/dist/cjs/middleware/cache/cache.js.map +1 -0
  50. package/dist/cjs/middleware/cache/index.d.ts +44 -0
  51. package/dist/cjs/middleware/cache/index.d.ts.map +1 -0
  52. package/dist/cjs/middleware/cache/index.js +50 -0
  53. package/dist/cjs/middleware/cache/index.js.map +1 -0
  54. package/dist/cjs/middleware/cache/types.d.ts +89 -0
  55. package/dist/cjs/middleware/cache/types.d.ts.map +1 -0
  56. package/dist/cjs/middleware/cache/types.js +6 -0
  57. package/dist/cjs/middleware/cache/types.js.map +1 -0
  58. package/dist/cjs/middleware/csrf/csrf.d.ts +34 -0
  59. package/dist/cjs/middleware/csrf/csrf.d.ts.map +1 -0
  60. package/dist/cjs/middleware/csrf/csrf.js +94 -0
  61. package/dist/cjs/middleware/csrf/csrf.js.map +1 -0
  62. package/dist/cjs/middleware/csrf/index.d.ts +57 -0
  63. package/dist/cjs/middleware/csrf/index.d.ts.map +1 -0
  64. package/dist/cjs/middleware/csrf/index.js +62 -0
  65. package/dist/cjs/middleware/csrf/index.js.map +1 -0
  66. package/dist/cjs/middleware/csrf/types.d.ts +57 -0
  67. package/dist/cjs/middleware/csrf/types.d.ts.map +1 -0
  68. package/dist/cjs/middleware/csrf/types.js +6 -0
  69. package/dist/cjs/middleware/csrf/types.js.map +1 -0
  70. package/dist/cjs/middleware/index.d.ts +115 -0
  71. package/dist/cjs/middleware/index.d.ts.map +1 -0
  72. package/dist/cjs/middleware/index.js +153 -0
  73. package/dist/cjs/middleware/index.js.map +1 -0
  74. package/dist/cjs/middleware/logging/index.d.ts +42 -0
  75. package/dist/cjs/middleware/logging/index.d.ts.map +1 -0
  76. package/dist/cjs/middleware/logging/index.js +47 -0
  77. package/dist/cjs/middleware/logging/index.js.map +1 -0
  78. package/dist/cjs/middleware/logging/logging.d.ts +29 -0
  79. package/dist/cjs/middleware/logging/logging.d.ts.map +1 -0
  80. package/dist/cjs/middleware/logging/logging.js +171 -0
  81. package/dist/cjs/middleware/logging/logging.js.map +1 -0
  82. package/dist/cjs/middleware/logging/types.d.ts +90 -0
  83. package/dist/cjs/middleware/logging/types.d.ts.map +1 -0
  84. package/dist/cjs/middleware/logging/types.js +6 -0
  85. package/dist/cjs/middleware/logging/types.js.map +1 -0
  86. package/dist/cjs/middleware/rate-limit/index.d.ts +16 -0
  87. package/dist/cjs/middleware/rate-limit/index.d.ts.map +1 -0
  88. package/dist/cjs/middleware/rate-limit/index.js +21 -0
  89. package/dist/cjs/middleware/rate-limit/index.js.map +1 -0
  90. package/dist/cjs/middleware/rate-limit/rate-limit.d.ts +14 -0
  91. package/dist/cjs/middleware/rate-limit/rate-limit.d.ts.map +1 -0
  92. package/dist/cjs/middleware/rate-limit/rate-limit.js +87 -0
  93. package/dist/cjs/middleware/rate-limit/rate-limit.js.map +1 -0
  94. package/dist/cjs/middleware/rate-limit/types.d.ts +97 -0
  95. package/dist/cjs/middleware/rate-limit/types.d.ts.map +1 -0
  96. package/dist/cjs/middleware/rate-limit/types.js +6 -0
  97. package/dist/cjs/middleware/rate-limit/types.js.map +1 -0
  98. package/dist/cjs/middleware/retry/index.d.ts +6 -0
  99. package/dist/cjs/middleware/retry/index.d.ts.map +1 -0
  100. package/dist/cjs/middleware/retry/index.js +11 -0
  101. package/dist/cjs/middleware/retry/index.js.map +1 -0
  102. package/dist/cjs/middleware/retry/retry.d.ts +39 -0
  103. package/dist/cjs/middleware/retry/retry.d.ts.map +1 -0
  104. package/dist/cjs/middleware/retry/retry.js +144 -0
  105. package/dist/cjs/middleware/retry/retry.js.map +1 -0
  106. package/dist/cjs/middleware/retry/types.d.ts +61 -0
  107. package/dist/cjs/middleware/retry/types.d.ts.map +1 -0
  108. package/dist/cjs/middleware/retry/types.js +6 -0
  109. package/dist/cjs/middleware/retry/types.js.map +1 -0
  110. package/dist/client/fetch-client.d.ts +189 -0
  111. package/dist/client/fetch-client.d.ts.map +1 -0
  112. package/dist/client/fetch-client.js +335 -0
  113. package/dist/client/fetch-client.js.map +1 -0
  114. package/dist/client/index.d.ts +11 -0
  115. package/dist/client/index.d.ts.map +1 -0
  116. package/dist/client/index.js +10 -0
  117. package/dist/client/index.js.map +1 -0
  118. package/dist/client/types.d.ts +63 -0
  119. package/dist/client/types.d.ts.map +1 -0
  120. package/dist/client/types.js +8 -0
  121. package/dist/client/types.js.map +1 -0
  122. package/dist/errors/index.d.ts +64 -0
  123. package/dist/errors/index.d.ts.map +1 -0
  124. package/dist/errors/index.js +73 -0
  125. package/dist/errors/index.js.map +1 -0
  126. package/dist/index.d.ts +49 -20
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +86 -42
  129. package/dist/index.js.map +1 -1
  130. package/dist/middleware/authentication/authentication.d.ts +31 -0
  131. package/dist/middleware/authentication/authentication.d.ts.map +1 -0
  132. package/dist/middleware/authentication/authentication.js +90 -0
  133. package/dist/middleware/authentication/authentication.js.map +1 -0
  134. package/dist/middleware/authentication/index.d.ts +37 -0
  135. package/dist/middleware/authentication/index.d.ts.map +1 -0
  136. package/dist/middleware/authentication/index.js +37 -0
  137. package/dist/middleware/authentication/index.js.map +1 -0
  138. package/dist/middleware/authentication/types.d.ts +73 -0
  139. package/dist/middleware/authentication/types.d.ts.map +1 -0
  140. package/dist/middleware/authentication/types.js +5 -0
  141. package/dist/middleware/authentication/types.js.map +1 -0
  142. package/dist/middleware/authorization/authorization.d.ts +30 -0
  143. package/dist/middleware/authorization/authorization.d.ts.map +1 -0
  144. package/dist/middleware/authorization/authorization.js +79 -0
  145. package/dist/middleware/authorization/authorization.js.map +1 -0
  146. package/dist/middleware/authorization/index.d.ts +36 -0
  147. package/dist/middleware/authorization/index.d.ts.map +1 -0
  148. package/dist/middleware/authorization/index.js +36 -0
  149. package/dist/middleware/authorization/index.js.map +1 -0
  150. package/dist/middleware/authorization/types.d.ts +67 -0
  151. package/dist/middleware/authorization/types.d.ts.map +1 -0
  152. package/dist/middleware/authorization/types.js +5 -0
  153. package/dist/middleware/authorization/types.js.map +1 -0
  154. package/dist/middleware/cache/cache.d.ts +41 -0
  155. package/dist/middleware/cache/cache.d.ts.map +1 -0
  156. package/dist/middleware/cache/cache.js +186 -0
  157. package/dist/middleware/cache/cache.js.map +1 -0
  158. package/dist/middleware/cache/index.d.ts +44 -0
  159. package/dist/middleware/cache/index.d.ts.map +1 -0
  160. package/dist/middleware/cache/index.js +44 -0
  161. package/dist/middleware/cache/index.js.map +1 -0
  162. package/dist/middleware/cache/types.d.ts +89 -0
  163. package/dist/middleware/cache/types.d.ts.map +1 -0
  164. package/dist/middleware/cache/types.js +5 -0
  165. package/dist/middleware/cache/types.js.map +1 -0
  166. package/dist/middleware/csrf/csrf.d.ts +34 -0
  167. package/dist/middleware/csrf/csrf.d.ts.map +1 -0
  168. package/dist/middleware/csrf/csrf.js +91 -0
  169. package/dist/middleware/csrf/csrf.js.map +1 -0
  170. package/dist/middleware/csrf/index.d.ts +57 -0
  171. package/dist/middleware/csrf/index.d.ts.map +1 -0
  172. package/dist/middleware/csrf/index.js +57 -0
  173. package/dist/middleware/csrf/index.js.map +1 -0
  174. package/dist/middleware/csrf/types.d.ts +57 -0
  175. package/dist/middleware/csrf/types.d.ts.map +1 -0
  176. package/dist/middleware/csrf/types.js +5 -0
  177. package/dist/middleware/csrf/types.js.map +1 -0
  178. package/dist/middleware/index.d.ts +115 -0
  179. package/dist/middleware/index.d.ts.map +1 -0
  180. package/dist/middleware/index.js +134 -0
  181. package/dist/middleware/index.js.map +1 -0
  182. package/dist/middleware/logging/index.d.ts +42 -0
  183. package/dist/middleware/logging/index.d.ts.map +1 -0
  184. package/dist/middleware/logging/index.js +42 -0
  185. package/dist/middleware/logging/index.js.map +1 -0
  186. package/dist/middleware/logging/logging.d.ts +29 -0
  187. package/dist/middleware/logging/logging.d.ts.map +1 -0
  188. package/dist/middleware/logging/logging.js +168 -0
  189. package/dist/middleware/logging/logging.js.map +1 -0
  190. package/dist/middleware/logging/types.d.ts +90 -0
  191. package/dist/middleware/logging/types.d.ts.map +1 -0
  192. package/dist/middleware/logging/types.js +5 -0
  193. package/dist/middleware/logging/types.js.map +1 -0
  194. package/dist/middleware/rate-limit/index.d.ts +16 -0
  195. package/dist/middleware/rate-limit/index.d.ts.map +1 -0
  196. package/dist/middleware/rate-limit/index.js +16 -0
  197. package/dist/middleware/rate-limit/index.js.map +1 -0
  198. package/dist/middleware/rate-limit/rate-limit.d.ts +14 -0
  199. package/dist/middleware/rate-limit/rate-limit.d.ts.map +1 -0
  200. package/dist/middleware/rate-limit/rate-limit.js +84 -0
  201. package/dist/middleware/rate-limit/rate-limit.js.map +1 -0
  202. package/dist/middleware/rate-limit/types.d.ts +97 -0
  203. package/dist/middleware/rate-limit/types.d.ts.map +1 -0
  204. package/dist/middleware/rate-limit/types.js +5 -0
  205. package/dist/middleware/rate-limit/types.js.map +1 -0
  206. package/dist/middleware/retry/index.d.ts +6 -0
  207. package/dist/middleware/retry/index.d.ts.map +1 -0
  208. package/dist/middleware/retry/index.js +6 -0
  209. package/dist/middleware/retry/index.js.map +1 -0
  210. package/dist/middleware/retry/retry.d.ts +39 -0
  211. package/dist/middleware/retry/retry.d.ts.map +1 -0
  212. package/dist/middleware/retry/retry.js +141 -0
  213. package/dist/middleware/retry/retry.js.map +1 -0
  214. package/dist/middleware/retry/types.d.ts +61 -0
  215. package/dist/middleware/retry/types.d.ts.map +1 -0
  216. package/dist/middleware/retry/types.js +5 -0
  217. package/dist/middleware/retry/types.js.map +1 -0
  218. package/package.json +42 -8
  219. package/dist/client.d.ts +0 -133
  220. package/dist/client.js +0 -166
  221. package/dist/client.js.map +0 -1
  222. package/dist/csrf.d.ts +0 -32
  223. package/dist/csrf.js +0 -53
  224. package/dist/csrf.js.map +0 -1
  225. package/dist/errors.js.map +0 -1
  226. package/dist/test-utils.d.ts +0 -24
  227. package/dist/test-utils.js +0 -52
  228. package/dist/test-utils.js.map +0 -1
  229. package/dist/unauthorized.d.ts +0 -27
  230. package/dist/unauthorized.js +0 -41
  231. package/dist/unauthorized.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @fileoverview Rate limiting middleware implementation.
3
+ */
4
+ /**
5
+ * Simple token bucket implementation for rate limiting.
6
+ */
7
+ class TokenBucket {
8
+ constructor(maxTokens, refillRate, // tokens per millisecond
9
+ timeProvider = () => Date.now()) {
10
+ this.maxTokens = maxTokens;
11
+ this.refillRate = refillRate;
12
+ this.timeProvider = timeProvider;
13
+ this.tokens = maxTokens;
14
+ this.lastRefill = this.timeProvider();
15
+ }
16
+ tryConsume() {
17
+ this.refill();
18
+ if (this.tokens >= 1) {
19
+ this.tokens--;
20
+ return { allowed: true };
21
+ }
22
+ // Calculate when next token will be available
23
+ const retryAfter = (1 - this.tokens) / this.refillRate;
24
+ return { allowed: false, retryAfter: Math.ceil(retryAfter) };
25
+ }
26
+ refill() {
27
+ const now = this.timeProvider();
28
+ const timePassed = now - this.lastRefill;
29
+ const tokensToAdd = timePassed * this.refillRate;
30
+ this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
31
+ this.lastRefill = now;
32
+ }
33
+ }
34
+ /**
35
+ * Creates rate limiting middleware - mainly for API quota management.
36
+ * Note: Rate limiting is typically a server concern, but this can help with:
37
+ * - Respecting API provider limits
38
+ * - Preventing runaway requests in bulk operations
39
+ * - Cost management for pay-per-request APIs
40
+ */
41
+ export function createRateLimitMiddleware(options = {}) {
42
+ const { maxRequests = 60, windowMs = 60000, keyGenerator = () => 'default', skipPatterns = [], onRateLimitExceeded, } = options;
43
+ const buckets = new Map();
44
+ const refillRate = maxRequests / windowMs;
45
+ return async (request, next) => {
46
+ const url = request.url || '';
47
+ // Skip rate limiting if URL matches skip patterns
48
+ if (skipPatterns.some((pattern) => typeof pattern === 'string' ? url.includes(pattern) : pattern.test(url))) {
49
+ return next(request);
50
+ }
51
+ const key = keyGenerator(request);
52
+ if (!buckets.has(key)) {
53
+ buckets.set(key, new TokenBucket(maxRequests, refillRate));
54
+ }
55
+ const bucket = buckets.get(key);
56
+ const result = bucket.tryConsume();
57
+ if (!result.allowed) {
58
+ if (onRateLimitExceeded) {
59
+ const customResponse = await onRateLimitExceeded(result.retryAfter || 0, request);
60
+ // If the custom handler returns a response, use it
61
+ if (customResponse) {
62
+ return customResponse;
63
+ }
64
+ }
65
+ // Return a 429 Too Many Requests response instead of throwing
66
+ return {
67
+ data: null,
68
+ status: 429,
69
+ statusText: 'Too Many Requests',
70
+ headers: new Headers({
71
+ 'Retry-After': Math.ceil((result.retryAfter || 0) / 1000).toString(),
72
+ }),
73
+ url: request.url || '',
74
+ ok: false,
75
+ error: {
76
+ message: `Rate limit exceeded. Retry after ${result.retryAfter}ms`,
77
+ body: { retryAfter: result.retryAfter },
78
+ },
79
+ };
80
+ }
81
+ return next(request);
82
+ };
83
+ }
84
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../../src/middleware/rate-limit/rate-limit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @fileoverview Rate limiting middleware types and configuration.
3
+ */
4
+ /**
5
+ * Rate limiting algorithm types.
6
+ */
7
+ export type RateLimitAlgorithm = 'token-bucket' | 'sliding-window' | 'fixed-window';
8
+ /**
9
+ * Rate limiting configuration options - optimized for "pit of success".
10
+ *
11
+ * Smart defaults:
12
+ * - 60 requests per minute
13
+ * - Token bucket algorithm
14
+ * - Per-client limiting
15
+ * - Graceful handling when rate limit exceeded
16
+ */
17
+ export interface RateLimitOptions {
18
+ /**
19
+ * Maximum number of requests allowed (default: 60)
20
+ */
21
+ maxRequests?: number;
22
+ /**
23
+ * Time window in milliseconds (default: 60000 = 1 minute)
24
+ */
25
+ windowMs?: number;
26
+ /**
27
+ * Rate limiting algorithm (default: 'token-bucket')
28
+ * - 'token-bucket': Allows bursts up to maxRequests, refills over time
29
+ * - 'sliding-window': Smooth rate limiting over rolling window
30
+ * - 'fixed-window': Fixed number of requests per fixed time window
31
+ */
32
+ algorithm?: RateLimitAlgorithm;
33
+ /**
34
+ * Custom key generator for rate limiting scope
35
+ * Default: single global rate limit for all requests
36
+ *
37
+ * @example Per-endpoint rate limiting:
38
+ * ```typescript
39
+ * keyGenerator: (request) => request.url || 'default'
40
+ * ```
41
+ *
42
+ * @example Per-user rate limiting:
43
+ * ```typescript
44
+ * keyGenerator: (request) => {
45
+ * const auth = request.headers?.get('Authorization');
46
+ * return auth ? `user:${auth}` : 'anonymous';
47
+ * }
48
+ * ```
49
+ */
50
+ keyGenerator?: (request: RequestInit & {
51
+ url?: string;
52
+ }) => string;
53
+ /**
54
+ * Skip rate limiting for requests matching these URL patterns
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * skipPatterns: ['/health', /^\/public\//]
59
+ * ```
60
+ */
61
+ skipPatterns?: (RegExp | string)[];
62
+ /**
63
+ * Custom handler called when rate limit is exceeded
64
+ * Can return a custom response or void to use default behavior
65
+ *
66
+ * @param retryAfter - Milliseconds until next request is allowed
67
+ * @param request - The rate-limited request
68
+ * @returns Custom response or void for default behavior
69
+ */
70
+ onRateLimitExceeded?: (retryAfter: number, request: RequestInit & {
71
+ url?: string;
72
+ }) => void | Promise<void> | {
73
+ data: unknown;
74
+ status: number;
75
+ statusText: string;
76
+ headers: Headers;
77
+ url: string;
78
+ ok: boolean;
79
+ error?: {
80
+ message: string;
81
+ body?: unknown;
82
+ };
83
+ } | Promise<{
84
+ data: unknown;
85
+ status: number;
86
+ statusText: string;
87
+ headers: Headers;
88
+ url: string;
89
+ ok: boolean;
90
+ error?: {
91
+ message: string;
92
+ body?: unknown;
93
+ };
94
+ }>;
95
+ }
96
+ export {};
97
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/middleware/rate-limit/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,gBAAgB,GAChB,cAAc,CAAC;AAEnB;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;IAEnE;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAEnC;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,CACpB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KACpC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG;QAC1B,IAAI,EAAE,OAAO,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KAC7C,GAAG,OAAO,CAAC;QACV,IAAI,EAAE,OAAO,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KAC7C,CAAC,CAAC;CACJ;AAGD,OAAO,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview Rate limiting middleware types and configuration.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/middleware/rate-limit/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,6 @@
1
+ import type { FetchClient } from '../../client/fetch-client';
2
+ import type { RetryOptions } from './types';
3
+ export type { RetryOptions } from './types';
4
+ export { createRetryMiddleware } from './retry';
5
+ export declare function useRetry(client: FetchClient, options?: RetryOptions): FetchClient;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/retry/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEhD,wBAAgB,QAAQ,CACtB,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,YAAiB,GACzB,WAAW,CAEb"}
@@ -0,0 +1,6 @@
1
+ import { createRetryMiddleware } from './retry';
2
+ export { createRetryMiddleware } from './retry';
3
+ export function useRetry(client, options = {}) {
4
+ return client.use(createRetryMiddleware(options));
5
+ }
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/middleware/retry/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEhD,MAAM,UAAU,QAAQ,CACtB,MAAmB,EACnB,UAAwB,EAAE;IAE1B,OAAO,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @fileoverview Retry middleware implementation with enhanced architecture.
3
+ */
4
+ import type { FetchMiddleware } from '../../client/fetch-client';
5
+ import type { RetryOptions } from './types';
6
+ /**
7
+ * Creates a retry middleware with smart defaults.
8
+ *
9
+ * 🎯 PIT OF SUCCESS: Works great with no config, customizable when needed.
10
+ *
11
+ * Features:
12
+ * - ✅ Preserves full middleware chain on retries (unlike old implementation)
13
+ * - ✅ Exponential backoff with jitter
14
+ * - ✅ Smart retry conditions (network errors + 5xx)
15
+ * - ✅ Configurable but sensible defaults
16
+ * - ✅ Type-safe configuration
17
+ *
18
+ * @param options - Retry configuration (all optional)
19
+ * @returns Middleware function
20
+ *
21
+ * @example Basic usage:
22
+ * ```typescript
23
+ * const client = new FetchClient();
24
+ * client.use(createRetryMiddleware()); // 3 retries with exponential backoff
25
+ * ```
26
+ *
27
+ * @example Custom configuration:
28
+ * ```typescript
29
+ * const client = new FetchClient();
30
+ * client.use(createRetryMiddleware({
31
+ * maxRetries: 5,
32
+ * delay: 500,
33
+ * backoff: 'linear',
34
+ * onRetry: (attempt, delay) => console.log(`Retry ${attempt} in ${delay}ms`)
35
+ * }));
36
+ * ```
37
+ */
38
+ export declare function createRetryMiddleware(options?: RetryOptions): FetchMiddleware;
39
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../src/middleware/retry/retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAgD5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,YAAiB,GACzB,eAAe,CAgGjB"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @fileoverview Retry middleware implementation with enhanced architecture.
3
+ */
4
+ /**
5
+ * Default retry condition - retry on network errors and 5xx server errors.
6
+ */
7
+ const defaultShouldRetry = (response) => {
8
+ // Network errors (status 0) or server errors (5xx)
9
+ return (response.status === 0 || (response.status >= 500 && response.status < 600));
10
+ };
11
+ /**
12
+ * Calculate delay for retry attempt based on backoff strategy.
13
+ */
14
+ const calculateDelay = (attempt, baseDelay, backoff, maxDelay) => {
15
+ let delay;
16
+ switch (backoff) {
17
+ case 'exponential':
18
+ delay = baseDelay * Math.pow(2, attempt - 1);
19
+ break;
20
+ case 'linear':
21
+ delay = baseDelay * attempt;
22
+ break;
23
+ case 'fixed':
24
+ default:
25
+ delay = baseDelay;
26
+ break;
27
+ }
28
+ return Math.min(delay, maxDelay);
29
+ };
30
+ /**
31
+ * Sleep for specified duration.
32
+ */
33
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
34
+ /**
35
+ * Creates a retry middleware with smart defaults.
36
+ *
37
+ * 🎯 PIT OF SUCCESS: Works great with no config, customizable when needed.
38
+ *
39
+ * Features:
40
+ * - ✅ Preserves full middleware chain on retries (unlike old implementation)
41
+ * - ✅ Exponential backoff with jitter
42
+ * - ✅ Smart retry conditions (network errors + 5xx)
43
+ * - ✅ Configurable but sensible defaults
44
+ * - ✅ Type-safe configuration
45
+ *
46
+ * @param options - Retry configuration (all optional)
47
+ * @returns Middleware function
48
+ *
49
+ * @example Basic usage:
50
+ * ```typescript
51
+ * const client = new FetchClient();
52
+ * client.use(createRetryMiddleware()); // 3 retries with exponential backoff
53
+ * ```
54
+ *
55
+ * @example Custom configuration:
56
+ * ```typescript
57
+ * const client = new FetchClient();
58
+ * client.use(createRetryMiddleware({
59
+ * maxRetries: 5,
60
+ * delay: 500,
61
+ * backoff: 'linear',
62
+ * onRetry: (attempt, delay) => console.log(`Retry ${attempt} in ${delay}ms`)
63
+ * }));
64
+ * ```
65
+ */
66
+ export function createRetryMiddleware(options = {}) {
67
+ const { maxRetries = 3, delay = 1000, backoff = 'exponential', maxDelay = 30000, shouldRetry = defaultShouldRetry, onRetry, } = options;
68
+ return async (request, next) => {
69
+ let lastResponse;
70
+ let attempt = 0;
71
+ while (attempt <= maxRetries) {
72
+ try {
73
+ // Execute the request through the middleware chain
74
+ const response = await next(request);
75
+ // If successful, return immediately
76
+ if (response.ok) {
77
+ return response;
78
+ }
79
+ // Check if we should retry this response with current attempt count
80
+ if (!shouldRetry({ status: response.status, ok: response.ok }, attempt + 1)) {
81
+ return response;
82
+ }
83
+ // If we've reached max retries, return the response
84
+ if (attempt >= maxRetries) {
85
+ return response;
86
+ }
87
+ // Store the failed response and increment attempt counter
88
+ lastResponse = response;
89
+ attempt++;
90
+ // Calculate delay for next attempt
91
+ const retryDelay = calculateDelay(attempt, delay, backoff, maxDelay);
92
+ // Call onRetry callback if provided
93
+ if (onRetry) {
94
+ onRetry(attempt, retryDelay, {
95
+ status: response.status,
96
+ statusText: response.statusText,
97
+ });
98
+ }
99
+ // Wait before retrying
100
+ await sleep(retryDelay);
101
+ }
102
+ catch (error) {
103
+ // Handle unexpected errors - treat as network error (status 0)
104
+ const errorResponse = {
105
+ data: null,
106
+ status: 0,
107
+ statusText: 'Network Error',
108
+ headers: new Headers(),
109
+ url: request.url || '',
110
+ ok: false,
111
+ error: {
112
+ message: error instanceof Error ? error.message : 'Unknown error',
113
+ body: error,
114
+ },
115
+ };
116
+ // If shouldn't retry, return error immediately
117
+ if (!shouldRetry(errorResponse, attempt + 1)) {
118
+ return errorResponse;
119
+ }
120
+ // If we've reached max retries, return the error
121
+ if (attempt >= maxRetries) {
122
+ return errorResponse;
123
+ }
124
+ lastResponse = errorResponse;
125
+ attempt++;
126
+ // Calculate delay for next attempt
127
+ const retryDelay = calculateDelay(attempt, delay, backoff, maxDelay);
128
+ if (onRetry) {
129
+ onRetry(attempt, retryDelay, {
130
+ status: errorResponse.status,
131
+ statusText: errorResponse.statusText,
132
+ });
133
+ }
134
+ await sleep(retryDelay);
135
+ }
136
+ }
137
+ // Return the last response if we've exhausted all retries
138
+ return lastResponse;
139
+ };
140
+ }
141
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/middleware/retry/retry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview Retry middleware types and configuration.
3
+ */
4
+ /**
5
+ * Retry configuration options - optimized for "pit of success".
6
+ *
7
+ * Smart defaults:
8
+ * - 3 retries (4 total attempts)
9
+ * - Exponential backoff starting at 1000ms
10
+ * - Only retry on network errors and 5xx status codes
11
+ */
12
+ export interface RetryOptions {
13
+ /**
14
+ * Maximum number of retry attempts (default: 3)
15
+ * Total attempts will be maxRetries + 1
16
+ */
17
+ maxRetries?: number;
18
+ /**
19
+ * Initial delay in milliseconds (default: 1000)
20
+ * Subsequent delays use exponential backoff
21
+ */
22
+ delay?: number;
23
+ /**
24
+ * Backoff strategy (default: 'exponential')
25
+ * - 'exponential': delay * (2 ^ attempt)
26
+ * - 'linear': delay * attempt
27
+ * - 'fixed': always use delay
28
+ */
29
+ backoff?: 'exponential' | 'linear' | 'fixed';
30
+ /**
31
+ * Maximum delay cap in milliseconds (default: 30000 = 30s)
32
+ * Prevents exponential backoff from getting too large
33
+ */
34
+ maxDelay?: number;
35
+ /**
36
+ * Custom function to determine if a response should be retried
37
+ * Default: retry on network errors (status 0) and server errors (5xx)
38
+ *
39
+ * @param response - The fetch response or error
40
+ * @param attempt - Current attempt number (1-based)
41
+ * @returns true if request should be retried
42
+ */
43
+ shouldRetry?: (response: {
44
+ status: number;
45
+ ok: boolean;
46
+ }, attempt: number) => boolean;
47
+ /**
48
+ * Optional callback called before each retry attempt
49
+ * Useful for logging or analytics
50
+ *
51
+ * @param attempt - Current attempt number (1-based)
52
+ * @param delay - Delay before this retry in ms
53
+ * @param lastResponse - The failed response that triggered the retry
54
+ */
55
+ onRetry?: (attempt: number, delay: number, lastResponse: {
56
+ status: number;
57
+ statusText: string;
58
+ }) => void;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/middleware/retry/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE7C;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,CACZ,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAA;KAAE,EACzC,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC;IAEb;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CACR,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KACjD,IAAI,CAAC;CACX;AAGD,OAAO,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview Retry middleware types and configuration.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/middleware/retry/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json CHANGED
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "name": "@fgrzl/fetch",
3
- "version": "1.1.0-alpha.3",
4
- "description": "A simple fetch client with some extra goodies",
3
+ "version": "1.1.0-alpha.8",
4
+ "description": "A modern, type-safe HTTP client with middleware support for CSRF protection and authentication",
5
5
  "keywords": [
6
6
  "fetch",
7
7
  "typescript",
8
- "api"
8
+ "api",
9
+ "http",
10
+ "client",
11
+ "middleware",
12
+ "CSRF",
13
+ "auth",
14
+ "type-safe"
9
15
  ],
10
16
  "homepage": "https://github.com/fgrzl/fetch#readme",
11
17
  "bugs": {
@@ -17,28 +23,56 @@
17
23
  },
18
24
  "license": "MIT",
19
25
  "author": "smiggleworth",
20
- "type": "commonjs",
26
+ "type": "module",
27
+ "engines": {
28
+ "node": ">=18.0.0"
29
+ },
21
30
  "main": "dist/index.js",
31
+ "module": "dist/index.js",
22
32
  "types": "dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js",
37
+ "require": "./dist/cjs/index.js"
38
+ }
39
+ },
23
40
  "files": [
24
41
  "dist"
25
42
  ],
43
+ "overrides": {
44
+ "@typescript-eslint/utils": "^8.39.1"
45
+ },
26
46
  "scripts": {
27
- "build": "tsc",
28
- "prepublishOnly": "npm run build",
47
+ "build": "npm run build:esm && npm run build:cjs",
48
+ "build:esm": "tsc",
49
+ "build:cjs": "tsc -p tsconfig.cjs.json",
50
+ "clean": "rimraf dist",
51
+ "prepublishOnly": "npm run clean && npm run build",
29
52
  "format": "prettier --write .",
30
53
  "format:check": "prettier --check .",
54
+ "lint": "eslint src --ext .ts",
55
+ "lint:fix": "eslint src --ext .ts --fix",
56
+ "lint:check": "npm run lint && npm run format:check",
31
57
  "test": "vitest run",
32
58
  "test:watch": "vitest --watch",
33
- "test:coverage": "vitest run --coverage",
34
- "lint": "npm run format:check"
59
+ "test:coverage": "vitest run --coverage"
35
60
  },
36
61
  "devDependencies": {
62
+ "@eslint/js": "^9.33.0",
37
63
  "@types/node": "^24.2.1",
64
+ "@typescript-eslint/eslint-plugin": "^8.39.1",
65
+ "@typescript-eslint/parser": "^8.39.1",
38
66
  "@vitest/coverage-v8": "^3.2.4",
67
+ "eslint": "^9.33.0",
68
+ "eslint-config-prettier": "^10.1.8",
69
+ "eslint-plugin-vitest": "^0.5.4",
70
+ "jiti": "^2.5.1",
39
71
  "jsdom": "^26.1.0",
40
72
  "prettier": "^3.6.2",
73
+ "rimraf": "^6.0.1",
41
74
  "typescript": "^5.9.2",
75
+ "typescript-eslint": "^8.39.1",
42
76
  "vitest": "^3.2.4"
43
77
  }
44
78
  }