@http-client-toolkit/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025, Ally Murray
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @http-client-toolkit/core
2
+
3
+ Core HTTP client with pluggable caching, deduplication, and rate limiting. Part of the [http-client-toolkit](https://github.com/AllyMurray/http-client-toolkit) monorepo.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @http-client-toolkit/core
9
+ ```
10
+
11
+ Requires Node.js >= 20.
12
+
13
+ You'll also need at least one store backend:
14
+
15
+ ```bash
16
+ npm install @http-client-toolkit/store-memory
17
+ # or
18
+ npm install @http-client-toolkit/store-sqlite
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { HttpClient } from '@http-client-toolkit/core';
25
+ import {
26
+ InMemoryCacheStore,
27
+ InMemoryDedupeStore,
28
+ InMemoryRateLimitStore,
29
+ } from '@http-client-toolkit/store-memory';
30
+
31
+ const client = new HttpClient(
32
+ {
33
+ cache: new InMemoryCacheStore(),
34
+ dedupe: new InMemoryDedupeStore(),
35
+ rateLimit: new InMemoryRateLimitStore(),
36
+ },
37
+ { defaultCacheTTL: 300 },
38
+ );
39
+
40
+ const data = await client.get<{ name: string }>(
41
+ 'https://api.example.com/user/1',
42
+ );
43
+ ```
44
+
45
+ Every store is optional. Use only what you need:
46
+
47
+ ```typescript
48
+ // Cache-only client
49
+ const client = new HttpClient({ cache: new InMemoryCacheStore() });
50
+
51
+ // Rate-limited client with no caching
52
+ const client = new HttpClient({
53
+ rateLimit: new InMemoryRateLimitStore({
54
+ defaultConfig: { limit: 100, windowMs: 60_000 },
55
+ }),
56
+ });
57
+ ```
58
+
59
+ ## API
60
+
61
+ ### `new HttpClient(stores?, options?)`
62
+
63
+ `HttpClient` exposes a single request method: `get(url, options?)`. The `url` must be an absolute URL.
64
+
65
+ **Request options (`client.get`)**
66
+
67
+ | Property | Type | Default | Description |
68
+ | ---------- | ------------------------ | -------------- | ----------------------------------- |
69
+ | `signal` | `AbortSignal` | - | Cancels wait + request when aborted |
70
+ | `priority` | `'user' \| 'background'` | `'background'` | Used by adaptive rate-limit stores |
71
+
72
+ **Stores:**
73
+
74
+ | Property | Type | Description |
75
+ | ----------- | ------------------------------------------ | --------------------- |
76
+ | `cache` | `CacheStore` | Response caching |
77
+ | `dedupe` | `DedupeStore` | Request deduplication |
78
+ | `rateLimit` | `RateLimitStore \| AdaptiveRateLimitStore` | Rate limiting |
79
+
80
+ **Options:**
81
+
82
+ | Property | Type | Default | Description |
83
+ | --------------------- | ---------------------------- | -------- | --------------------------------------- |
84
+ | `defaultCacheTTL` | `number` | `3600` | Cache TTL in seconds |
85
+ | `throwOnRateLimit` | `boolean` | `true` | Throw when rate limited vs. wait |
86
+ | `maxWaitTime` | `number` | `60000` | Max wait time (ms) before throwing |
87
+ | `responseTransformer` | `(data: unknown) => unknown` | - | Transform raw response data |
88
+ | `responseHandler` | `(data: unknown) => unknown` | - | Validate/process transformed data |
89
+ | `errorHandler` | `(error: unknown) => Error` | - | Convert errors to domain-specific types |
90
+ | `rateLimitHeaders` | `RateLimitHeaderConfig` | defaults | Configure standard/custom header names |
91
+
92
+ ### Request Flow
93
+
94
+ 1. **Cache** - Return cached response if available
95
+ 2. **Dedupe** - If an identical request is already in-flight, wait for its result
96
+ 3. **Rate Limit** - Wait or throw if the rate limit is exceeded
97
+ 4. **Fetch** - Execute the HTTP request
98
+ 5. **Transform & Validate** - Apply `responseTransformer` then `responseHandler`
99
+ 6. **Store** - Cache the result, record the rate limit hit, and resolve any deduplicated waiters
100
+
101
+ ### Error Handling
102
+
103
+ All HTTP errors are wrapped in `HttpClientError`:
104
+
105
+ ```typescript
106
+ import { HttpClientError } from '@http-client-toolkit/core';
107
+
108
+ try {
109
+ await client.get(url);
110
+ } catch (error) {
111
+ if (error instanceof HttpClientError) {
112
+ console.log(error.message);
113
+ console.log(error.statusCode);
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### Cancellation
119
+
120
+ Pass an `AbortSignal` to cancel a request, including while waiting for a rate limit window:
121
+
122
+ ```typescript
123
+ const controller = new AbortController();
124
+ const data = await client.get(url, { signal: controller.signal });
125
+ controller.abort();
126
+ ```
127
+
128
+ ### Header-Based Rate Limiting
129
+
130
+ `HttpClient` respects server-provided rate-limit headers out of the box:
131
+
132
+ - `Retry-After`
133
+ - `RateLimit-Remaining` / `RateLimit-Reset`
134
+ - `X-RateLimit-Remaining` / `X-RateLimit-Reset`
135
+
136
+ Map non-standard header names per API:
137
+
138
+ ```typescript
139
+ const client = new HttpClient(
140
+ {},
141
+ {
142
+ rateLimitHeaders: {
143
+ retryAfter: ['RetryAfterSeconds'],
144
+ remaining: ['Remaining-Requests'],
145
+ reset: ['Window-Reset-Seconds'],
146
+ },
147
+ },
148
+ );
149
+ ```
150
+
151
+ ### Exports
152
+
153
+ - `HttpClient` - Main client class
154
+ - `HttpClientError` - Error class with `statusCode`
155
+ - `hashRequest` - Deterministic SHA-256 request hashing
156
+ - Store interfaces: `CacheStore`, `DedupeStore`, `RateLimitStore`, `AdaptiveRateLimitStore`
157
+
158
+ ## License
159
+
160
+ ISC