@fuman/fetch 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 +8 -0
- package/README.md +13 -0
- package/_types.d.ts +8 -0
- package/addons/_utils.cjs +54 -0
- package/addons/_utils.d.ts +3 -0
- package/addons/_utils.js +54 -0
- package/addons/bundle.cjs +18 -0
- package/addons/bundle.d.ts +7 -0
- package/addons/bundle.js +18 -0
- package/addons/form.cjs +23 -0
- package/addons/form.d.ts +22 -0
- package/addons/form.js +23 -0
- package/addons/index.d.ts +3 -0
- package/addons/multipart.cjs +35 -0
- package/addons/multipart.d.ts +22 -0
- package/addons/multipart.js +35 -0
- package/addons/parse/_types.d.ts +11 -0
- package/addons/parse/adapters/valibot.d.ts +8 -0
- package/addons/parse/adapters/yup.d.ts +13 -0
- package/addons/parse/adapters/zod.d.ts +6 -0
- package/addons/parse/addon.cjs +12 -0
- package/addons/parse/addon.d.ts +6 -0
- package/addons/parse/addon.js +12 -0
- package/addons/query.cjs +22 -0
- package/addons/query.d.ts +17 -0
- package/addons/query.js +22 -0
- package/addons/rate-limit.cjs +65 -0
- package/addons/rate-limit.d.ts +62 -0
- package/addons/rate-limit.js +65 -0
- package/addons/retry.cjs +74 -0
- package/addons/retry.d.ts +58 -0
- package/addons/retry.js +74 -0
- package/addons/timeout.cjs +54 -0
- package/addons/timeout.d.ts +25 -0
- package/addons/timeout.js +54 -0
- package/addons/tough-cookie.d.ts +7 -0
- package/addons/types.d.ts +30 -0
- package/default.cjs +18 -0
- package/default.d.ts +30 -0
- package/default.js +18 -0
- package/ffetch.cjs +200 -0
- package/ffetch.d.ts +101 -0
- package/ffetch.js +200 -0
- package/index.cjs +10 -0
- package/index.d.ts +4 -0
- package/index.js +10 -0
- package/package.json +89 -0
- package/tough.cjs +24 -0
- package/tough.d.ts +1 -0
- package/tough.js +24 -0
- package/valibot.cjs +16 -0
- package/valibot.d.ts +1 -0
- package/valibot.js +16 -0
- package/yup.cjs +18 -0
- package/yup.d.ts +1 -0
- package/yup.js +18 -0
- package/zod.cjs +15 -0
- package/zod.d.ts +1 -0
- package/zod.js +15 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { sleep } from "@fuman/utils";
|
|
2
|
+
const defaultIsRejected = (res) => res.status === 429;
|
|
3
|
+
const defaultGetReset = (res) => res.headers.get("x-ratelimit-reset");
|
|
4
|
+
function tryParseDate(str) {
|
|
5
|
+
if (str == null) return null;
|
|
6
|
+
if (typeof str === "number") return str * 1e3;
|
|
7
|
+
const asNum = Number(str);
|
|
8
|
+
if (!Number.isNaN(asNum)) return asNum * 1e3;
|
|
9
|
+
const asDate = new Date(str);
|
|
10
|
+
if (asDate.toString() === "Invalid Date") return null;
|
|
11
|
+
return asDate.getTime();
|
|
12
|
+
}
|
|
13
|
+
function rateLimitMiddleware(options) {
|
|
14
|
+
const {
|
|
15
|
+
isRejected = defaultIsRejected,
|
|
16
|
+
getReset = defaultGetReset,
|
|
17
|
+
defaultWaitTime = 3e4,
|
|
18
|
+
maxWaitTime = 3e5,
|
|
19
|
+
jitter = 5e3,
|
|
20
|
+
maxRetries = 5,
|
|
21
|
+
onRateLimitExceeded
|
|
22
|
+
} = options;
|
|
23
|
+
return async (req, next) => {
|
|
24
|
+
let attempts = 0;
|
|
25
|
+
while (true) {
|
|
26
|
+
if (attempts > maxRetries) throw new Error("Rate limit exceeded, maximum retries exceeded");
|
|
27
|
+
attempts += 1;
|
|
28
|
+
const res = await next(req);
|
|
29
|
+
const rejected = await isRejected(res);
|
|
30
|
+
if (!rejected) return res;
|
|
31
|
+
const reset = tryParseDate(await getReset(res));
|
|
32
|
+
let waitTime;
|
|
33
|
+
if (reset == null) {
|
|
34
|
+
waitTime = defaultWaitTime;
|
|
35
|
+
} else {
|
|
36
|
+
waitTime = reset - Date.now() + jitter;
|
|
37
|
+
if (waitTime < 0) {
|
|
38
|
+
waitTime = void 0;
|
|
39
|
+
} else if (waitTime > maxWaitTime) {
|
|
40
|
+
throw new Error(`Rate limit exceeded, reset time is too far in the future: ${new Date(reset).toISOString()}`, { cause: res });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (waitTime == null) {
|
|
44
|
+
onRateLimitExceeded?.(res, 0);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
onRateLimitExceeded?.(res, waitTime);
|
|
48
|
+
await sleep(waitTime);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function rateLimitHandler() {
|
|
53
|
+
return {
|
|
54
|
+
beforeRequest: (ctx) => {
|
|
55
|
+
if (ctx.options.rateLimit != null || ctx.baseOptions.rateLimit != null) {
|
|
56
|
+
const options = { ...ctx.baseOptions.rateLimit, ...ctx.options.rateLimit };
|
|
57
|
+
ctx.options.middlewares ??= [];
|
|
58
|
+
ctx.options.middlewares?.push(rateLimitMiddleware(options));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
rateLimitHandler
|
|
65
|
+
};
|
package/addons/retry.cjs
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const utils = require("@fuman/utils");
|
|
4
|
+
class RetriesExceededError extends Error {
|
|
5
|
+
constructor(retries, request) {
|
|
6
|
+
super(`Retries (${retries}) exceeded for ${request.url}`);
|
|
7
|
+
this.retries = retries;
|
|
8
|
+
this.request = request;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function defaultRetryDelay(retryCount) {
|
|
12
|
+
if (retryCount >= 5) return 5e3;
|
|
13
|
+
return retryCount * 1e3;
|
|
14
|
+
}
|
|
15
|
+
function retryMiddleware(options) {
|
|
16
|
+
const {
|
|
17
|
+
maxRetries = 5,
|
|
18
|
+
retryDelay = defaultRetryDelay,
|
|
19
|
+
onResponse = (response) => response.status < 500,
|
|
20
|
+
returnLastResponse = false,
|
|
21
|
+
onError,
|
|
22
|
+
onRetry,
|
|
23
|
+
skip
|
|
24
|
+
} = options;
|
|
25
|
+
return async (request, next) => {
|
|
26
|
+
if (skip?.(request)) {
|
|
27
|
+
return next(request);
|
|
28
|
+
}
|
|
29
|
+
let retries = 0;
|
|
30
|
+
while (true) {
|
|
31
|
+
onRetry?.(retries, request);
|
|
32
|
+
try {
|
|
33
|
+
const res = await next(request);
|
|
34
|
+
if (onResponse(res, request)) {
|
|
35
|
+
return res;
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
if (onError && !onError(err, request)) {
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (retries++ >= maxRetries) {
|
|
43
|
+
throw new RetriesExceededError(maxRetries, request);
|
|
44
|
+
}
|
|
45
|
+
await utils.sleep(typeof retryDelay === "function" ? retryDelay(retries) : retryDelay);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function retry() {
|
|
50
|
+
return {
|
|
51
|
+
beforeRequest: (ctx) => {
|
|
52
|
+
if (ctx.options.retry != null || ctx.baseOptions.retry != null) {
|
|
53
|
+
let options;
|
|
54
|
+
if (ctx.baseOptions.retry != null) {
|
|
55
|
+
if (ctx.options.retry === false) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
options = ctx.options.retry ? {
|
|
59
|
+
...ctx.baseOptions.retry,
|
|
60
|
+
...ctx.options.retry
|
|
61
|
+
} : ctx.baseOptions.retry;
|
|
62
|
+
} else if (ctx.options.retry === false) {
|
|
63
|
+
return;
|
|
64
|
+
} else {
|
|
65
|
+
options = ctx.options.retry;
|
|
66
|
+
}
|
|
67
|
+
ctx.options.middlewares ??= [];
|
|
68
|
+
ctx.options.middlewares.push(retryMiddleware(options));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
exports.RetriesExceededError = RetriesExceededError;
|
|
74
|
+
exports.retry = retry;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { FfetchAddon } from './types.js';
|
|
2
|
+
export declare class RetriesExceededError extends Error {
|
|
3
|
+
readonly retries: number;
|
|
4
|
+
readonly request: Request;
|
|
5
|
+
constructor(retries: number, request: Request);
|
|
6
|
+
}
|
|
7
|
+
export interface RetryOptions {
|
|
8
|
+
/**
|
|
9
|
+
* max number of retries
|
|
10
|
+
* @default 5
|
|
11
|
+
*/
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
/**
|
|
14
|
+
* delay between retries
|
|
15
|
+
* @default retryCount * 1000, up to 5000
|
|
16
|
+
*/
|
|
17
|
+
retryDelay?: number | ((retryCount: number) => number);
|
|
18
|
+
/**
|
|
19
|
+
* function that will be called before starting the retry loop.
|
|
20
|
+
* if it returns false, the retry loop will be skipped and
|
|
21
|
+
* the error will be thrown immediately
|
|
22
|
+
*
|
|
23
|
+
* @default () => false
|
|
24
|
+
*/
|
|
25
|
+
skip?: (request: Request) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* function that will be called before a retry is attempted,
|
|
28
|
+
* and can be used to modify the request before proceeding
|
|
29
|
+
*
|
|
30
|
+
* @param attempt current retry attempt (starts at 0)
|
|
31
|
+
*/
|
|
32
|
+
onRetry?: (attempt: number, request: Request) => Request | void;
|
|
33
|
+
/**
|
|
34
|
+
* function that will be called whenever a response is received,
|
|
35
|
+
* and should return whether the response is valid (i.e. should be returned and not retried)
|
|
36
|
+
*
|
|
37
|
+
* @default `response => response.status < 500`
|
|
38
|
+
*/
|
|
39
|
+
onResponse?: (response: Response, request: Request) => boolean;
|
|
40
|
+
/**
|
|
41
|
+
* function that will be called if an error is thrown while calling
|
|
42
|
+
* the rest of the middleware chain,
|
|
43
|
+
* and should return whether the error should be retried
|
|
44
|
+
*
|
|
45
|
+
* @default `() => true`
|
|
46
|
+
*/
|
|
47
|
+
onError?: (err: unknown, request: Request) => boolean;
|
|
48
|
+
/**
|
|
49
|
+
* if true, the last response will be returned if the number of retries is exceeded
|
|
50
|
+
* instead of throwing {@link RetriesExceededError}
|
|
51
|
+
*
|
|
52
|
+
* @default false
|
|
53
|
+
*/
|
|
54
|
+
returnLastResponse?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare function retry(): FfetchAddon<{
|
|
57
|
+
retry?: RetryOptions | false;
|
|
58
|
+
}, object>;
|
package/addons/retry.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { sleep } from "@fuman/utils";
|
|
2
|
+
class RetriesExceededError extends Error {
|
|
3
|
+
constructor(retries, request) {
|
|
4
|
+
super(`Retries (${retries}) exceeded for ${request.url}`);
|
|
5
|
+
this.retries = retries;
|
|
6
|
+
this.request = request;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function defaultRetryDelay(retryCount) {
|
|
10
|
+
if (retryCount >= 5) return 5e3;
|
|
11
|
+
return retryCount * 1e3;
|
|
12
|
+
}
|
|
13
|
+
function retryMiddleware(options) {
|
|
14
|
+
const {
|
|
15
|
+
maxRetries = 5,
|
|
16
|
+
retryDelay = defaultRetryDelay,
|
|
17
|
+
onResponse = (response) => response.status < 500,
|
|
18
|
+
returnLastResponse = false,
|
|
19
|
+
onError,
|
|
20
|
+
onRetry,
|
|
21
|
+
skip
|
|
22
|
+
} = options;
|
|
23
|
+
return async (request, next) => {
|
|
24
|
+
if (skip?.(request)) {
|
|
25
|
+
return next(request);
|
|
26
|
+
}
|
|
27
|
+
let retries = 0;
|
|
28
|
+
while (true) {
|
|
29
|
+
onRetry?.(retries, request);
|
|
30
|
+
try {
|
|
31
|
+
const res = await next(request);
|
|
32
|
+
if (onResponse(res, request)) {
|
|
33
|
+
return res;
|
|
34
|
+
}
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (onError && !onError(err, request)) {
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (retries++ >= maxRetries) {
|
|
41
|
+
throw new RetriesExceededError(maxRetries, request);
|
|
42
|
+
}
|
|
43
|
+
await sleep(typeof retryDelay === "function" ? retryDelay(retries) : retryDelay);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function retry() {
|
|
48
|
+
return {
|
|
49
|
+
beforeRequest: (ctx) => {
|
|
50
|
+
if (ctx.options.retry != null || ctx.baseOptions.retry != null) {
|
|
51
|
+
let options;
|
|
52
|
+
if (ctx.baseOptions.retry != null) {
|
|
53
|
+
if (ctx.options.retry === false) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
options = ctx.options.retry ? {
|
|
57
|
+
...ctx.baseOptions.retry,
|
|
58
|
+
...ctx.options.retry
|
|
59
|
+
} : ctx.baseOptions.retry;
|
|
60
|
+
} else if (ctx.options.retry === false) {
|
|
61
|
+
return;
|
|
62
|
+
} else {
|
|
63
|
+
options = ctx.options.retry;
|
|
64
|
+
}
|
|
65
|
+
ctx.options.middlewares ??= [];
|
|
66
|
+
ctx.options.middlewares.push(retryMiddleware(options));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
RetriesExceededError,
|
|
73
|
+
retry
|
|
74
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const utils = require("@fuman/utils");
|
|
4
|
+
class TimeoutError extends Error {
|
|
5
|
+
constructor(timeout2) {
|
|
6
|
+
super(`Timeout exceeded: ${timeout2}ms`);
|
|
7
|
+
this.timeout = timeout2;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function timeoutMiddleware(timeout2) {
|
|
11
|
+
return async (request, next) => {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timer = utils.timers.setTimeout(() => {
|
|
14
|
+
controller.abort(new TimeoutError(timeout2));
|
|
15
|
+
}, timeout2);
|
|
16
|
+
if (request.signal != null) {
|
|
17
|
+
const signal = request.signal;
|
|
18
|
+
if (signal.aborted) {
|
|
19
|
+
throw signal.reason;
|
|
20
|
+
}
|
|
21
|
+
signal.addEventListener("abort", () => {
|
|
22
|
+
controller.abort(signal.reason);
|
|
23
|
+
utils.timers.clearTimeout(timer);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
request = new Request(request, {
|
|
27
|
+
signal: controller.signal
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
return await next(request);
|
|
31
|
+
} finally {
|
|
32
|
+
utils.timers.clearTimeout(timer);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function timeout() {
|
|
37
|
+
return {
|
|
38
|
+
beforeRequest: (ctx) => {
|
|
39
|
+
if (ctx.options.timeout != null || ctx.baseOptions.timeout != null) {
|
|
40
|
+
let timeout2 = ctx.options.timeout ?? ctx.baseOptions.timeout;
|
|
41
|
+
if (typeof timeout2 === "function") {
|
|
42
|
+
timeout2 = timeout2(ctx);
|
|
43
|
+
}
|
|
44
|
+
if (timeout2 === Infinity || timeout2 <= 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
ctx.options.middlewares ??= [];
|
|
48
|
+
ctx.options.middlewares?.push(timeoutMiddleware(timeout2));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.TimeoutError = TimeoutError;
|
|
54
|
+
exports.timeout = timeout;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FetchAddonCtx, FfetchAddon } from './types.js';
|
|
2
|
+
export declare class TimeoutError extends Error {
|
|
3
|
+
readonly timeout: number;
|
|
4
|
+
constructor(timeout: number);
|
|
5
|
+
}
|
|
6
|
+
export interface TimeoutAddon {
|
|
7
|
+
/**
|
|
8
|
+
* timeout for the request in ms
|
|
9
|
+
*
|
|
10
|
+
* pass `Infinity` or `0` to disable the default timeout from the base options
|
|
11
|
+
*
|
|
12
|
+
* when the timeout is reached, the request will be aborted
|
|
13
|
+
* and the promise will be rejected with a TimeoutError
|
|
14
|
+
*/
|
|
15
|
+
timeout?: number | ((ctx: FetchAddonCtx<TimeoutAddon>) => number);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* ffetch addon that allows setting a timeout for the request.
|
|
19
|
+
* when the timeout is reached, the request will be aborted
|
|
20
|
+
* and the promise will be rejected with a TimeoutError
|
|
21
|
+
*
|
|
22
|
+
* **note**: it is important to put this addon as the last one,
|
|
23
|
+
* otherwise other middlewares might be counted towards the timeout
|
|
24
|
+
*/
|
|
25
|
+
export declare function timeout(): FfetchAddon<TimeoutAddon, object>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { timers } from "@fuman/utils";
|
|
2
|
+
class TimeoutError extends Error {
|
|
3
|
+
constructor(timeout2) {
|
|
4
|
+
super(`Timeout exceeded: ${timeout2}ms`);
|
|
5
|
+
this.timeout = timeout2;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
function timeoutMiddleware(timeout2) {
|
|
9
|
+
return async (request, next) => {
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
const timer = timers.setTimeout(() => {
|
|
12
|
+
controller.abort(new TimeoutError(timeout2));
|
|
13
|
+
}, timeout2);
|
|
14
|
+
if (request.signal != null) {
|
|
15
|
+
const signal = request.signal;
|
|
16
|
+
if (signal.aborted) {
|
|
17
|
+
throw signal.reason;
|
|
18
|
+
}
|
|
19
|
+
signal.addEventListener("abort", () => {
|
|
20
|
+
controller.abort(signal.reason);
|
|
21
|
+
timers.clearTimeout(timer);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
request = new Request(request, {
|
|
25
|
+
signal: controller.signal
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
return await next(request);
|
|
29
|
+
} finally {
|
|
30
|
+
timers.clearTimeout(timer);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function timeout() {
|
|
35
|
+
return {
|
|
36
|
+
beforeRequest: (ctx) => {
|
|
37
|
+
if (ctx.options.timeout != null || ctx.baseOptions.timeout != null) {
|
|
38
|
+
let timeout2 = ctx.options.timeout ?? ctx.baseOptions.timeout;
|
|
39
|
+
if (typeof timeout2 === "function") {
|
|
40
|
+
timeout2 = timeout2(ctx);
|
|
41
|
+
}
|
|
42
|
+
if (timeout2 === Infinity || timeout2 <= 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
ctx.options.middlewares ??= [];
|
|
46
|
+
ctx.options.middlewares?.push(timeoutMiddleware(timeout2));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
TimeoutError,
|
|
53
|
+
timeout
|
|
54
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CookieJar } from 'tough-cookie';
|
|
2
|
+
import { FfetchAddon } from './types.js';
|
|
3
|
+
export interface FfetchToughCookieAddon {
|
|
4
|
+
/** cookie jar to use */
|
|
5
|
+
cookies?: CookieJar;
|
|
6
|
+
}
|
|
7
|
+
export declare function toughCookieAddon(): FfetchAddon<FfetchToughCookieAddon, object>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { FfetchOptions, FfetchResult } from '../ffetch.js';
|
|
2
|
+
/**
|
|
3
|
+
* context that is passed to each addon in the order they were added
|
|
4
|
+
* you can safely modify anything in this object
|
|
5
|
+
*/
|
|
6
|
+
export interface FetchAddonCtx<RequestMixin extends object> {
|
|
7
|
+
/** url of the request (with baseUrl already applied) */
|
|
8
|
+
url: string;
|
|
9
|
+
/** options of this specific request */
|
|
10
|
+
options: FfetchOptions & RequestMixin;
|
|
11
|
+
/** base options passed to `createFfetch` */
|
|
12
|
+
baseOptions: FfetchOptions & RequestMixin;
|
|
13
|
+
}
|
|
14
|
+
/** internals that are exposed to the functions in response mixin */
|
|
15
|
+
export type FfetchResultInternals<RequestMixin extends object> = FfetchResult & {
|
|
16
|
+
/** final url of the request */
|
|
17
|
+
_url: string;
|
|
18
|
+
/** request init object that will be passed to fetch */
|
|
19
|
+
_init: RequestInit;
|
|
20
|
+
/** finalized and merged options */
|
|
21
|
+
_options: FfetchOptions & RequestMixin;
|
|
22
|
+
/** finalized and merged headers */
|
|
23
|
+
_headers?: Record<string, string>;
|
|
24
|
+
};
|
|
25
|
+
export interface FfetchAddon<RequestMixin extends object, ResponseMixin extends object> {
|
|
26
|
+
/** function that will be called before each request */
|
|
27
|
+
beforeRequest?: (ctx: FetchAddonCtx<RequestMixin>) => void;
|
|
28
|
+
/** mixin functions that will be added to the response promise */
|
|
29
|
+
response?: ResponseMixin;
|
|
30
|
+
}
|
package/default.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const ffetch = require("./ffetch.cjs");
|
|
4
|
+
const timeout = require("./addons/timeout.cjs");
|
|
5
|
+
const query = require("./addons/query.cjs");
|
|
6
|
+
const form = require("./addons/form.cjs");
|
|
7
|
+
const multipart = require("./addons/multipart.cjs");
|
|
8
|
+
const ffetchDefaultAddons = [
|
|
9
|
+
/* @__PURE__ */ timeout.timeout(),
|
|
10
|
+
/* @__PURE__ */ query.query(),
|
|
11
|
+
/* @__PURE__ */ form.form(),
|
|
12
|
+
/* @__PURE__ */ multipart.multipart()
|
|
13
|
+
];
|
|
14
|
+
const ffetchBase = /* @__PURE__ */ ffetch.createFfetch({
|
|
15
|
+
addons: ffetchDefaultAddons
|
|
16
|
+
});
|
|
17
|
+
exports.ffetchBase = ffetchBase;
|
|
18
|
+
exports.ffetchDefaultAddons = ffetchDefaultAddons;
|
package/default.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { FfetchAddon, ffetchAddons } from './addons/index.js';
|
|
2
|
+
import { Ffetch } from './ffetch.js';
|
|
3
|
+
export declare const ffetchDefaultAddons: [
|
|
4
|
+
FfetchAddon<ffetchAddons.TimeoutAddon, object>,
|
|
5
|
+
FfetchAddon<ffetchAddons.QueryAddon, object>,
|
|
6
|
+
FfetchAddon<ffetchAddons.FormAddon, object>,
|
|
7
|
+
FfetchAddon<ffetchAddons.MultipartAddon, object>
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* the default ffetch instance with reasonable default set of addons
|
|
11
|
+
*
|
|
12
|
+
* you can use this as a base to create your project-specific fetch instance,
|
|
13
|
+
* or use this as is.
|
|
14
|
+
*
|
|
15
|
+
* this is not exported as `ffetch` because most of the time you will want to extend it,
|
|
16
|
+
* and exporting it as `ffetch` would make them clash in import suggestions,
|
|
17
|
+
* and will also make it prone to subtle bugs.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { ffetchBase } from '@fuman/fetch'
|
|
22
|
+
*
|
|
23
|
+
* const ffetch = ffetchBase.extend({
|
|
24
|
+
* baseUrl: 'https://example.com',
|
|
25
|
+
* headers: { ... },
|
|
26
|
+
* addons: [ ... ],
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare const ffetchBase: Ffetch<ffetchAddons.TimeoutAddon & ffetchAddons.QueryAddon & ffetchAddons.FormAddon & ffetchAddons.MultipartAddon, object>;
|
package/default.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createFfetch } from "./ffetch.js";
|
|
2
|
+
import { timeout } from "./addons/timeout.js";
|
|
3
|
+
import { query } from "./addons/query.js";
|
|
4
|
+
import { form } from "./addons/form.js";
|
|
5
|
+
import { multipart } from "./addons/multipart.js";
|
|
6
|
+
const ffetchDefaultAddons = [
|
|
7
|
+
/* @__PURE__ */ timeout(),
|
|
8
|
+
/* @__PURE__ */ query(),
|
|
9
|
+
/* @__PURE__ */ form(),
|
|
10
|
+
/* @__PURE__ */ multipart()
|
|
11
|
+
];
|
|
12
|
+
const ffetchBase = /* @__PURE__ */ createFfetch({
|
|
13
|
+
addons: ffetchDefaultAddons
|
|
14
|
+
});
|
|
15
|
+
export {
|
|
16
|
+
ffetchBase,
|
|
17
|
+
ffetchDefaultAddons
|
|
18
|
+
};
|