laihui 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/README.md +403 -0
- package/dist/core/compose.d.ts +3 -0
- package/dist/core/compose.d.ts.map +1 -0
- package/dist/core/compose.js +12 -0
- package/dist/core/compose.js.map +1 -0
- package/dist/core/createFetch.d.ts +3 -0
- package/dist/core/createFetch.d.ts.map +1 -0
- package/dist/core/createFetch.js +99 -0
- package/dist/core/createFetch.js.map +1 -0
- package/dist/core/request.d.ts +3 -0
- package/dist/core/request.d.ts.map +1 -0
- package/dist/core/request.js +69 -0
- package/dist/core/request.js.map +1 -0
- package/dist/core/response.d.ts +3 -0
- package/dist/core/response.d.ts.map +1 -0
- package/dist/core/response.js +34 -0
- package/dist/core/response.js.map +1 -0
- package/dist/errors/index.d.ts +28 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +61 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth-refresh.d.ts +9 -0
- package/dist/middleware/auth-refresh.d.ts.map +1 -0
- package/dist/middleware/auth-refresh.js +45 -0
- package/dist/middleware/auth-refresh.js.map +1 -0
- package/dist/middleware/dedupe.d.ts +6 -0
- package/dist/middleware/dedupe.d.ts.map +1 -0
- package/dist/middleware/dedupe.js +28 -0
- package/dist/middleware/dedupe.js.map +1 -0
- package/dist/middleware/retry.d.ts +12 -0
- package/dist/middleware/retry.d.ts.map +1 -0
- package/dist/middleware/retry.js +69 -0
- package/dist/middleware/retry.js.map +1 -0
- package/dist/middleware/timeout.d.ts +6 -0
- package/dist/middleware/timeout.d.ts.map +1 -0
- package/dist/middleware/timeout.js +30 -0
- package/dist/middleware/timeout.js.map +1 -0
- package/dist/patch/download.d.ts +11 -0
- package/dist/patch/download.d.ts.map +1 -0
- package/dist/patch/download.js +164 -0
- package/dist/patch/download.js.map +1 -0
- package/dist/patch/pagination.d.ts +8 -0
- package/dist/patch/pagination.d.ts.map +1 -0
- package/dist/patch/pagination.js +162 -0
- package/dist/patch/pagination.js.map +1 -0
- package/dist/patch/poll.d.ts +8 -0
- package/dist/patch/poll.d.ts.map +1 -0
- package/dist/patch/poll.js +112 -0
- package/dist/patch/poll.js.map +1 -0
- package/dist/patch/resource.d.ts +7 -0
- package/dist/patch/resource.d.ts.map +1 -0
- package/dist/patch/resource.js +21 -0
- package/dist/patch/resource.js.map +1 -0
- package/dist/patch/upload/index.d.ts +13 -0
- package/dist/patch/upload/index.d.ts.map +1 -0
- package/dist/patch/upload/index.js +150 -0
- package/dist/patch/upload/index.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +10 -0
- package/dist/registry.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/instance.d.ts +23 -0
- package/dist/types/instance.d.ts.map +1 -0
- package/dist/types/instance.js +2 -0
- package/dist/types/instance.js.map +1 -0
- package/dist/types/method.d.ts +2 -0
- package/dist/types/method.d.ts.map +1 -0
- package/dist/types/method.js +2 -0
- package/dist/types/method.js.map +1 -0
- package/dist/types/middleware.d.ts +8 -0
- package/dist/types/middleware.d.ts.map +1 -0
- package/dist/types/middleware.js +2 -0
- package/dist/types/middleware.js.map +1 -0
- package/dist/types/options.d.ts +18 -0
- package/dist/types/options.d.ts.map +1 -0
- package/dist/types/options.js +2 -0
- package/dist/types/options.js.map +1 -0
- package/dist/types/pagination.d.ts +58 -0
- package/dist/types/pagination.d.ts.map +1 -0
- package/dist/types/pagination.js +2 -0
- package/dist/types/pagination.js.map +1 -0
- package/dist/types/poll.d.ts +27 -0
- package/dist/types/poll.d.ts.map +1 -0
- package/dist/types/poll.js +2 -0
- package/dist/types/poll.js.map +1 -0
- package/dist/types/resource.d.ts +12 -0
- package/dist/types/resource.d.ts.map +1 -0
- package/dist/types/resource.js +2 -0
- package/dist/types/resource.js.map +1 -0
- package/dist/types/transfer.d.ts +31 -0
- package/dist/types/transfer.d.ts.map +1 -0
- package/dist/types/transfer.js +2 -0
- package/dist/types/transfer.js.map +1 -0
- package/dist/utils/mergeHeaders.d.ts +2 -0
- package/dist/utils/mergeHeaders.d.ts.map +1 -0
- package/dist/utils/mergeHeaders.js +20 -0
- package/dist/utils/mergeHeaders.js.map +1 -0
- package/dist/utils/paramsSerializer.d.ts +3 -0
- package/dist/utils/paramsSerializer.d.ts.map +1 -0
- package/dist/utils/paramsSerializer.js +23 -0
- package/dist/utils/paramsSerializer.js.map +1 -0
- package/dist/utils/signal.d.ts +2 -0
- package/dist/utils/signal.d.ts.map +1 -0
- package/dist/utils/signal.js +12 -0
- package/dist/utils/signal.js.map +1 -0
- package/package.json +92 -0
package/README.md
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# laihui
|
|
2
|
+
|
|
3
|
+
A composable, middleware-driven HTTP client built on the Fetch API.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createFetch } from 'laihui'
|
|
7
|
+
|
|
8
|
+
const api = createFetch('https://api.example.com')
|
|
9
|
+
|
|
10
|
+
// Middleware pipeline (onion model)
|
|
11
|
+
api.use(async (ctx, next) => {
|
|
12
|
+
console.time(ctx.request.url)
|
|
13
|
+
await next()
|
|
14
|
+
console.timeEnd(ctx.request.url)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
// GET with type inference
|
|
18
|
+
const user = await api.get('/users/1').json<User>()
|
|
19
|
+
|
|
20
|
+
// POST with JSON body
|
|
21
|
+
const post = await api.post('/posts', {
|
|
22
|
+
body: { title: 'Hello', content: 'World' },
|
|
23
|
+
}).json()
|
|
24
|
+
|
|
25
|
+
// Extend instance
|
|
26
|
+
const admin = api.extend({
|
|
27
|
+
headers: { Authorization: 'Bearer token' },
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **Middleware pipeline** — Koa-style onion model, not flat hooks
|
|
34
|
+
- **Zero dependencies** in core
|
|
35
|
+
- **Universal** — Browser, Node 20+, Bun, Deno, Cloudflare Workers, Edge Runtime
|
|
36
|
+
- **TypeScript** — Strict mode, generics on `.json<T>()`
|
|
37
|
+
- **Tree-shakable** — ESM only, optional features via sub-path imports
|
|
38
|
+
- **Immutable** — `extend()` never mutates
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add laihui
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
### Basic
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const api = createFetch('https://api.example.com')
|
|
52
|
+
|
|
53
|
+
const data = await api.get('/users').json<User>()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Headers
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const api = createFetch('https://api.example.com').extend({
|
|
60
|
+
headers: { Authorization: 'Bearer token' },
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
await api.get('/users', {
|
|
64
|
+
headers: { 'X-Request-ID': 'abc' },
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Methods
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
api.get(url, options?)
|
|
72
|
+
api.post(url, options?)
|
|
73
|
+
api.put(url, options?)
|
|
74
|
+
api.patch(url, options?)
|
|
75
|
+
api.delete(url, options?)
|
|
76
|
+
api.head(url, options?)
|
|
77
|
+
api.options(url, options?)
|
|
78
|
+
api.trace(url, options?)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Response
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const res = api.get('/users')
|
|
85
|
+
await res // → Response
|
|
86
|
+
await res.json<T>() // → T
|
|
87
|
+
await res.text() // → string
|
|
88
|
+
await res.blob() // → Blob
|
|
89
|
+
await res.bytes() // → Uint8Array
|
|
90
|
+
await res.stream() // → ReadableStream
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Middleware
|
|
94
|
+
|
|
95
|
+
Use `.use(fn)` where `fn` is `(ctx, next) => Promise<void>`:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
api.use(async (ctx, next) => {
|
|
99
|
+
console.log('→', ctx.request.method, ctx.request.url)
|
|
100
|
+
await next()
|
|
101
|
+
console.log('←', ctx.response?.status)
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Share state between middlewares via `ctx.state`:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
api.use(async (ctx, next) => {
|
|
109
|
+
ctx.state.user = await getUser()
|
|
110
|
+
await next()
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Built-in Middleware
|
|
115
|
+
|
|
116
|
+
#### Timeout
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { timeout } from 'laihui/middleware/timeout'
|
|
120
|
+
|
|
121
|
+
api.use(timeout({ timeout: 5000 }))
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Retry
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { retry } from 'laihui/middleware/retry'
|
|
128
|
+
|
|
129
|
+
api.use(retry({
|
|
130
|
+
limit: 3,
|
|
131
|
+
delay: 1000,
|
|
132
|
+
backoff: 'exponential',
|
|
133
|
+
jitter: true,
|
|
134
|
+
statusCodes: [408, 413, 429, 500, 502, 503, 504],
|
|
135
|
+
}))
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Deduplication
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { dedupe } from 'laihui/middleware/dedupe'
|
|
142
|
+
|
|
143
|
+
api.use(dedupe())
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### Auth / Token Refresh
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { auth } from 'laihui/middleware/auth-refresh'
|
|
150
|
+
|
|
151
|
+
api.use(auth({
|
|
152
|
+
getToken: () => localStorage.getItem('token'),
|
|
153
|
+
refreshToken: async () => {
|
|
154
|
+
const newToken = await fetch('/refresh').then(r => r.text())
|
|
155
|
+
localStorage.setItem('token', newToken)
|
|
156
|
+
return newToken
|
|
157
|
+
},
|
|
158
|
+
}))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Error Handling
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import { HTTPError, TimeoutError, RetryError } from 'laihui'
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
await api.get('/users').json()
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (error instanceof HTTPError) {
|
|
170
|
+
console.error(error.response.status, error.response.statusText)
|
|
171
|
+
} else if (error instanceof TimeoutError) {
|
|
172
|
+
console.error('Request timed out')
|
|
173
|
+
} else if (error instanceof RetryError) {
|
|
174
|
+
console.error('Retry failed after', error.attempts, 'attempts')
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Extend
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const api = createFetch('https://api.example.com')
|
|
183
|
+
const admin = api.extend({
|
|
184
|
+
headers: { Authorization: 'Bearer admin' },
|
|
185
|
+
})
|
|
186
|
+
// api is not mutated — immutable
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Pagination
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import 'laihui/patch/pagination'
|
|
193
|
+
|
|
194
|
+
interface Page {
|
|
195
|
+
id: number
|
|
196
|
+
title: string
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const api = createFetch('https://api.example.com')
|
|
200
|
+
|
|
201
|
+
const pages = api.pagination<Page>('/api/pages', {
|
|
202
|
+
mode: 'page', // 'page' | 'cursor' | 'offset'
|
|
203
|
+
size: 20,
|
|
204
|
+
params: { status: 'published' },
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
const p1 = await pages.next()
|
|
208
|
+
// { items: Page[], total: 100, next: true, prev: false, page: 1, size: 20 }
|
|
209
|
+
|
|
210
|
+
const p2 = await pages.next() // page 2
|
|
211
|
+
const back = await pages.prev() // page 1
|
|
212
|
+
const jump = await pages.index(5) // page 5 (page mode only)
|
|
213
|
+
const again = await pages.reload()
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Polling
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import 'laihui/patch/poll'
|
|
220
|
+
|
|
221
|
+
const poll = api.poll<{ status: string }>('/jobs/1', {
|
|
222
|
+
interval: 2000,
|
|
223
|
+
condition: (data) => data.status === 'completed',
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
poll.on('data', (data) => console.log(data))
|
|
227
|
+
poll.on('done', (result) => console.log('Finished', result))
|
|
228
|
+
poll.on('error', (err) => console.error(err))
|
|
229
|
+
|
|
230
|
+
// Manual fetch
|
|
231
|
+
const result = await poll.next()
|
|
232
|
+
|
|
233
|
+
// Auto-polling
|
|
234
|
+
poll.start()
|
|
235
|
+
poll.stop()
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Download
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import 'laihui/patch/download'
|
|
242
|
+
|
|
243
|
+
const task = api.download('/files/report.pdf', {
|
|
244
|
+
onProgress: ({ transferred, total, percent }) => {
|
|
245
|
+
console.log(`${Math.round(percent * 100)}%`)
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
// Awaitable — resolves to Uint8Array (Node) or Blob (browser)
|
|
250
|
+
const data = await task
|
|
251
|
+
|
|
252
|
+
// Or with lifecycle controls
|
|
253
|
+
task.on('progress', (p) => console.log(p.percent))
|
|
254
|
+
task.on('done', (data) => console.log('done', data))
|
|
255
|
+
task.on('error', (err) => console.error(err))
|
|
256
|
+
task.pause() // aborts current request, keeps downloaded bytes
|
|
257
|
+
task.resume() // resumes via Range / If-Range from where it stopped
|
|
258
|
+
task.abort() // cancels
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Downloads run through the middleware pipeline. Pause/resume use HTTP
|
|
262
|
+
`Range` requests (with `If-Range` validation); if the server ignores
|
|
263
|
+
`Range` and returns `200`, the download restarts from scratch.
|
|
264
|
+
|
|
265
|
+
### Upload
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import 'laihui/patch/upload'
|
|
269
|
+
|
|
270
|
+
const task = api.upload('/files', file, {
|
|
271
|
+
onProgress: ({ transferred, total, percent }) => {
|
|
272
|
+
console.log(`${Math.round(percent * 100)}%`)
|
|
273
|
+
},
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
const response = await task // resolves to Response
|
|
277
|
+
|
|
278
|
+
task.on('progress', (p) => console.log(p.percent))
|
|
279
|
+
task.abort()
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Transport selection (`transport: 'auto' | 'fetch' | 'xhr'`, default `'auto'`):
|
|
283
|
+
|
|
284
|
+
- **`'auto'`** — feature-detects support for request streams. If supported,
|
|
285
|
+
uploads with progress via `fetch` + `duplex: 'half'`. If not supported and an
|
|
286
|
+
XHR fallback is provided (browser only), uses XHR. Otherwise it **warns** and
|
|
287
|
+
degrades to a progress-less upload.
|
|
288
|
+
- **`'fetch'`** — force `fetch` streaming.
|
|
289
|
+
- **`'xhr'`** — force XHR (requires the optional fallback transport).
|
|
290
|
+
|
|
291
|
+
The XHR transport is an opt-in module to keep the core pure-`fetch` and
|
|
292
|
+
tree-shakable:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
import { xhrTransport } from 'laihui/patch/upload/xhr'
|
|
296
|
+
|
|
297
|
+
api.upload('/files', file, {
|
|
298
|
+
transport: 'auto',
|
|
299
|
+
fallback: xhrTransport, // enables progress in HTTP/1.1 / Safari
|
|
300
|
+
onProgress: (p) => console.log(p.percent),
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Resource (CRUD)
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
import 'laihui/patch/resource'
|
|
308
|
+
|
|
309
|
+
const users = api.resource('/users')
|
|
310
|
+
|
|
311
|
+
// GET /users
|
|
312
|
+
const list = await users.list().json()
|
|
313
|
+
|
|
314
|
+
// GET /users/42
|
|
315
|
+
const user = await users.get(42).json()
|
|
316
|
+
|
|
317
|
+
// POST /users
|
|
318
|
+
const created = await users.create({ name: 'Alice' }).json()
|
|
319
|
+
|
|
320
|
+
// PUT /users/7
|
|
321
|
+
const updated = await users.update(7, { name: 'Bob' }).json()
|
|
322
|
+
|
|
323
|
+
// DELETE /users/99
|
|
324
|
+
await users.remove(99)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## API
|
|
328
|
+
|
|
329
|
+
### `createFetch(baseURL?: string)`
|
|
330
|
+
|
|
331
|
+
Returns a `FetchInstance`.
|
|
332
|
+
|
|
333
|
+
### `FetchInstance`
|
|
334
|
+
|
|
335
|
+
| Member | Description |
|
|
336
|
+
|--------|-------------|
|
|
337
|
+
| `.get(url, options?)` | GET request |
|
|
338
|
+
| `.post(url, options?)` | POST request |
|
|
339
|
+
| `.put(url, options?)` | PUT request |
|
|
340
|
+
| `.patch(url, options?)` | PATCH request |
|
|
341
|
+
| `.delete(url, options?)` | DELETE request |
|
|
342
|
+
| `.head(url, options?)` | HEAD request |
|
|
343
|
+
| `.options(url, options?)` | OPTIONS request |
|
|
344
|
+
| `.trace(url, options?)` | TRACE request |
|
|
345
|
+
| `.use(middleware)` | Register a middleware function |
|
|
346
|
+
| `.extend(options)` | Create a new immutable instance |
|
|
347
|
+
| `.pagination(url, config?, options?)` | Pagination helper (requires `import 'laihui/patch/pagination'`) |
|
|
348
|
+
| `.poll(url, config?)` | Polling helper (requires `import 'laihui/patch/poll'`) |
|
|
349
|
+
| `.resource(url, config?)` | CRUD helper (requires `import 'laihui/patch/resource'`) |
|
|
350
|
+
| `.download(url, config?)` | Download task helper (requires `import 'laihui/patch/download'`) |
|
|
351
|
+
| `.upload(url, file, config?)` | Upload task helper (requires `import 'laihui/patch/upload'`) |
|
|
352
|
+
|
|
353
|
+
### `FetchOptions`
|
|
354
|
+
|
|
355
|
+
Extends `RequestInit` (omitting `signal`, `body`).
|
|
356
|
+
|
|
357
|
+
| Option | Type | Description |
|
|
358
|
+
|--------|------|-------------|
|
|
359
|
+
| `baseURL` | `string` | Base URL for relative URL resolution |
|
|
360
|
+
| `headers` | `HeadersInit` | Default request headers |
|
|
361
|
+
| `json` | `boolean` | Default `true`. When `true`, `body` is treated as a `JsonValue`, automatically `JSON.stringify`-ed and sets `Content-Type: application/json`. When `false`, `body` is treated as raw `BodyInit \| null` |
|
|
362
|
+
| `body` | `JsonValue \| BodyInit \| null` | Request body. Type is narrowed based on `json`: when `json` is `true` (default), expected as `JsonValue`; when `json: false`, expected as `BodyInit \| null` |
|
|
363
|
+
| `signal` | `AbortSignal \| AbortSignal[]` | Single or multiple abort signals (merged automatically) |
|
|
364
|
+
| `params` | `URLSearchParamsInit` (`string \| URLSearchParams \| Iterable<[string, string \| number \| boolean]> \| Record<string, string \| number \| boolean>`) | Query parameters appended to URL (serialized via `URLSearchParams`; a raw `string` is used as-is). For complex serialization, pass the final value yourself, e.g. `params: qs.stringify(obj)` / `new URLSearchParams(obj)` / `new Map([...])` |
|
|
365
|
+
|
|
366
|
+
### `FetchResponse`
|
|
367
|
+
|
|
368
|
+
Thenable (awaitable to `Response` directly) with typed helpers:
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
interface FetchResponse extends PromiseLike<Response> {
|
|
372
|
+
json: <T = unknown>() => Promise<T>
|
|
373
|
+
text: () => Promise<string>
|
|
374
|
+
blob: () => Promise<Blob>
|
|
375
|
+
stream: () => Promise<ReadableStream<Uint8Array>>
|
|
376
|
+
bytes: () => Promise<Uint8Array>
|
|
377
|
+
clone: () => Promise<Response>
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The response body can only be consumed **once** (same as the native Fetch API).
|
|
382
|
+
To read it multiple times, clone before reading:
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
const res = await api.get('/users').clone()
|
|
386
|
+
const a = await res.json()
|
|
387
|
+
const b = await res.clone().text()
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Error Classes
|
|
391
|
+
|
|
392
|
+
| Class | Extends | Description |
|
|
393
|
+
|-------|---------|-------------|
|
|
394
|
+
| `FetchError` | `Error` | Base error with `.request` and `.cause` |
|
|
395
|
+
| `HTTPError` | `FetchError` | Non-ok response, has `.response` |
|
|
396
|
+
| `AbortError` | `FetchError` | Request was aborted |
|
|
397
|
+
| `TimeoutError` | `AbortError` | Request timed out |
|
|
398
|
+
| `RetryError` | `FetchError` | Retries exhausted, has `.attempts` |
|
|
399
|
+
| `NetworkError` | `FetchError` | Network failure, has optional `.code` |
|
|
400
|
+
|
|
401
|
+
## License
|
|
402
|
+
|
|
403
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/core/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAElE,wBAAgB,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAWtF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function compose(middlewares) {
|
|
2
|
+
return async (context) => {
|
|
3
|
+
const dispatch = async (i) => {
|
|
4
|
+
const middleware = middlewares[i];
|
|
5
|
+
if (!middleware)
|
|
6
|
+
return;
|
|
7
|
+
await middleware(context, () => dispatch(i + 1));
|
|
8
|
+
};
|
|
9
|
+
await dispatch(0);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/core/compose.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,OAAO,CAAC,WAAyB;IAC/C,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAS,EAAiB,EAAE;YAClD,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU;gBAAE,OAAO;YAExB,MAAM,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createFetch.d.ts","sourceRoot":"","sources":["../../src/core/createFetch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,sBAAsB,CAAC;AASzE,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAE1D"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { AbortError, getErrorCode, HTTPError, NetworkError } from '../errors/index.js';
|
|
2
|
+
import { applyPatches } from '../registry.js';
|
|
3
|
+
import { mergeHeaders } from '../utils/mergeHeaders.js';
|
|
4
|
+
import { compose } from './compose.js';
|
|
5
|
+
import { buildRequest } from './request.js';
|
|
6
|
+
import { createResponse } from './response.js';
|
|
7
|
+
export function createFetch(baseURL) {
|
|
8
|
+
return createFetchWithOptions({ baseURL });
|
|
9
|
+
}
|
|
10
|
+
const noopNext = async () => { };
|
|
11
|
+
function createFetchWithOptions(options) {
|
|
12
|
+
const middlewares = [];
|
|
13
|
+
let _pipeline;
|
|
14
|
+
const _interpolate = {
|
|
15
|
+
JSON: {
|
|
16
|
+
stringify: undefined,
|
|
17
|
+
parse: undefined,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
const fetchHandler = async (ctx) => {
|
|
21
|
+
try {
|
|
22
|
+
ctx.response = await fetch(ctx.request);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
26
|
+
throw new AbortError(ctx.request);
|
|
27
|
+
}
|
|
28
|
+
if (error instanceof TypeError) {
|
|
29
|
+
const cause = error instanceof Error ? error : undefined;
|
|
30
|
+
throw new NetworkError(ctx.request, cause, getErrorCode(error));
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
function pipe() {
|
|
36
|
+
if (!_pipeline) {
|
|
37
|
+
if (middlewares.length === 0) {
|
|
38
|
+
_pipeline = (ctx) => fetchHandler(ctx, noopNext);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
_pipeline = compose([...middlewares, fetchHandler]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return _pipeline;
|
|
45
|
+
}
|
|
46
|
+
async function execute(request) {
|
|
47
|
+
const context = {
|
|
48
|
+
request,
|
|
49
|
+
state: {},
|
|
50
|
+
};
|
|
51
|
+
await pipe()(context);
|
|
52
|
+
const response = context.response;
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
throw new HTTPError(`Response returned ${response.status}`, request, response);
|
|
55
|
+
}
|
|
56
|
+
return response;
|
|
57
|
+
}
|
|
58
|
+
function request(url, newOptions, method) {
|
|
59
|
+
const mergedOptions = {
|
|
60
|
+
...options,
|
|
61
|
+
...newOptions,
|
|
62
|
+
url,
|
|
63
|
+
method,
|
|
64
|
+
headers: mergeHeaders(newOptions?.headers, options.headers),
|
|
65
|
+
};
|
|
66
|
+
const request = buildRequest(mergedOptions, _interpolate.JSON.stringify);
|
|
67
|
+
return createResponse(execute(request), _interpolate.JSON.parse);
|
|
68
|
+
}
|
|
69
|
+
function createMethod(method) {
|
|
70
|
+
return (url, options) => request(url, options, method);
|
|
71
|
+
}
|
|
72
|
+
function use(middleware) {
|
|
73
|
+
middlewares.push(middleware);
|
|
74
|
+
_pipeline = undefined;
|
|
75
|
+
return api;
|
|
76
|
+
}
|
|
77
|
+
function extend(opt) {
|
|
78
|
+
const child = createFetchWithOptions({ ...options, ...opt });
|
|
79
|
+
for (const mw of middlewares) {
|
|
80
|
+
child.use(mw);
|
|
81
|
+
}
|
|
82
|
+
return child;
|
|
83
|
+
}
|
|
84
|
+
const api = {
|
|
85
|
+
get: createMethod('GET'),
|
|
86
|
+
post: createMethod('POST'),
|
|
87
|
+
put: createMethod('PUT'),
|
|
88
|
+
patch: createMethod('PATCH'),
|
|
89
|
+
delete: createMethod('DELETE'),
|
|
90
|
+
head: createMethod('HEAD'),
|
|
91
|
+
options: createMethod('OPTIONS'),
|
|
92
|
+
trace: createMethod('TRACE'),
|
|
93
|
+
use,
|
|
94
|
+
extend,
|
|
95
|
+
};
|
|
96
|
+
applyPatches(api);
|
|
97
|
+
return api;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=createFetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createFetch.js","sourceRoot":"","sources":["../../src/core/createFetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/core/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,SAAS,EAAuB,MAAM,qBAAqB,CAAC;AAIvG,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,MAAM,GAAG,OAAO,CAkBzG"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { paramsSerializer } from '../utils/paramsSerializer.js';
|
|
2
|
+
import { mergeSignals } from '../utils/signal.js';
|
|
3
|
+
export function buildRequest(options, stringifyJson) {
|
|
4
|
+
const { baseURL, url, params, headers, json, body, signal, ...rest } = options;
|
|
5
|
+
const resolvedURL = buildURL(baseURL, url, params);
|
|
6
|
+
const reqBody = buildBody(body, json, stringifyJson);
|
|
7
|
+
const reqHeaders = buildHeaders(headers, body, json);
|
|
8
|
+
const init = {
|
|
9
|
+
headers: reqHeaders,
|
|
10
|
+
body: reqBody,
|
|
11
|
+
signal: mergeSignals(options.signal),
|
|
12
|
+
...rest,
|
|
13
|
+
};
|
|
14
|
+
if (reqBody instanceof ReadableStream) {
|
|
15
|
+
init.duplex = 'half';
|
|
16
|
+
}
|
|
17
|
+
return new Request(resolvedURL, init);
|
|
18
|
+
}
|
|
19
|
+
function buildURL(baseURL, url, params) {
|
|
20
|
+
const resolved = url ?? '';
|
|
21
|
+
let result;
|
|
22
|
+
if (resolved.startsWith('http://') || resolved.startsWith('https://')) {
|
|
23
|
+
result = resolved;
|
|
24
|
+
}
|
|
25
|
+
else if (baseURL) {
|
|
26
|
+
const base = baseURL.endsWith('/') ? baseURL : `${baseURL}/`;
|
|
27
|
+
result = new URL(resolved, base).toString();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
result = resolved;
|
|
31
|
+
}
|
|
32
|
+
if (params) {
|
|
33
|
+
const query = paramsSerializer(params);
|
|
34
|
+
if (query) {
|
|
35
|
+
result += (result.includes('?') ? '&' : '?') + query;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function buildBody(body, json = true, stringifyJson = JSON.stringify) {
|
|
41
|
+
if (body == null)
|
|
42
|
+
return undefined;
|
|
43
|
+
if (json)
|
|
44
|
+
return stringifyJson(body);
|
|
45
|
+
return body;
|
|
46
|
+
}
|
|
47
|
+
function buildHeaders(headerInit, body, json) {
|
|
48
|
+
const headers = new Headers(headerInit);
|
|
49
|
+
if (body) {
|
|
50
|
+
let value;
|
|
51
|
+
if (json ?? true) {
|
|
52
|
+
value = 'application/json;charset=UTF-8';
|
|
53
|
+
}
|
|
54
|
+
else if (body instanceof URLSearchParams) {
|
|
55
|
+
value = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
56
|
+
}
|
|
57
|
+
else if (body instanceof Blob) {
|
|
58
|
+
value = body.type;
|
|
59
|
+
}
|
|
60
|
+
else if (typeof body === 'string') {
|
|
61
|
+
value = 'text/plain;charset=UTF-8';
|
|
62
|
+
}
|
|
63
|
+
if (value && !headers.has('Content-Type')) {
|
|
64
|
+
headers.set('Content-Type', value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return headers;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/core/request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/core/response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA8C1D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,aAAa,CAEhH"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class FetchResponseImpl {
|
|
2
|
+
#response;
|
|
3
|
+
#parseJson;
|
|
4
|
+
constructor(response, parseJson) {
|
|
5
|
+
this.#response = response;
|
|
6
|
+
this.#parseJson = parseJson;
|
|
7
|
+
}
|
|
8
|
+
json() {
|
|
9
|
+
return this.#response.then((r) => this.#parseJson ? r.text().then((t) => this.#parseJson?.(t)) : r.json());
|
|
10
|
+
}
|
|
11
|
+
text() {
|
|
12
|
+
return this.#response.then((r) => r.text());
|
|
13
|
+
}
|
|
14
|
+
blob() {
|
|
15
|
+
return this.#response.then((r) => r.blob());
|
|
16
|
+
}
|
|
17
|
+
stream() {
|
|
18
|
+
return this.#response.then((r) => r.body ?? new ReadableStream());
|
|
19
|
+
}
|
|
20
|
+
bytes() {
|
|
21
|
+
return this.#response.then((r) => r.bytes());
|
|
22
|
+
}
|
|
23
|
+
clone() {
|
|
24
|
+
return this.#response.then((r) => r.clone());
|
|
25
|
+
}
|
|
26
|
+
// biome-ignore lint/suspicious/noThenProperty: intentional thenable for await
|
|
27
|
+
then(onfulfilled, onrejected) {
|
|
28
|
+
return this.#response.then(onfulfilled, onrejected);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function createResponse(response, parseJson) {
|
|
32
|
+
return new FetchResponseImpl(response, parseJson);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/core/response.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB;IACZ,SAAS,CAAoB;IAC7B,UAAU,CAA6B;IAEhD,YAAY,QAA2B,EAAE,SAAqC;QAC5E,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC/B,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAM,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,IAAI,EAAiB,CAC7F,CAAC;IACJ,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,cAAc,EAAc,CAAC,CAAC;IAChF,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,8EAA8E;IAC9E,IAAI,CACF,WAA4E,EAC5E,UAA2E;QAE3E,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACtD,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,QAA2B,EAAE,SAAqC;IAC/F,OAAO,IAAI,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACpD,CAAC"}
|