@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
package/ffetch.cjs
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const utils = require("@fuman/utils");
|
|
4
|
+
const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
|
|
5
|
+
class HttpError extends Error {
|
|
6
|
+
constructor(response) {
|
|
7
|
+
super(`HTTP Error ${response.status} ${response.statusText}`);
|
|
8
|
+
this.response = response;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function headersToObject(headers) {
|
|
12
|
+
if (!headers) return {};
|
|
13
|
+
if (Array.isArray(headers) || headers instanceof Headers) return Object.fromEntries(headers);
|
|
14
|
+
if (Symbol.iterator in headers) {
|
|
15
|
+
return Object.fromEntries(headers);
|
|
16
|
+
}
|
|
17
|
+
return headers;
|
|
18
|
+
}
|
|
19
|
+
class FfetchResultImpl {
|
|
20
|
+
#fetch;
|
|
21
|
+
_url;
|
|
22
|
+
_init;
|
|
23
|
+
_options;
|
|
24
|
+
_headers;
|
|
25
|
+
#stack;
|
|
26
|
+
constructor(fetch2, url, init, headers, options, stack) {
|
|
27
|
+
this.#fetch = fetch2;
|
|
28
|
+
this._init = init;
|
|
29
|
+
this._url = url;
|
|
30
|
+
this._options = options;
|
|
31
|
+
this._headers = headers;
|
|
32
|
+
this.#stack = stack;
|
|
33
|
+
}
|
|
34
|
+
then(onfulfilled, onrejected) {
|
|
35
|
+
return this.raw().then(onfulfilled, onrejected);
|
|
36
|
+
}
|
|
37
|
+
catch(onrejected) {
|
|
38
|
+
return this.raw().catch(onrejected);
|
|
39
|
+
}
|
|
40
|
+
finally(onfinally) {
|
|
41
|
+
return this.raw().finally(onfinally);
|
|
42
|
+
}
|
|
43
|
+
get [Symbol.toStringTag]() {
|
|
44
|
+
return "FfetchResult";
|
|
45
|
+
}
|
|
46
|
+
async #fetchAndValidate() {
|
|
47
|
+
const res = await this.#fetch(new Request(this._url, this._init));
|
|
48
|
+
if (this._options.validateResponse === void 0 || this._options.validateResponse !== false) {
|
|
49
|
+
if (typeof this._options.validateResponse === "function") {
|
|
50
|
+
if (!await this._options.validateResponse(res)) {
|
|
51
|
+
throw new HttpError(res);
|
|
52
|
+
}
|
|
53
|
+
} else if (!res.ok) {
|
|
54
|
+
throw new HttpError(res);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return res;
|
|
58
|
+
}
|
|
59
|
+
async raw() {
|
|
60
|
+
if (this.#stack == null) return this.#fetchAndValidate();
|
|
61
|
+
try {
|
|
62
|
+
return await this.#fetchAndValidate();
|
|
63
|
+
} catch (err_) {
|
|
64
|
+
const err = utils.unknownToError(err_);
|
|
65
|
+
const errCopy = structuredClone(err_);
|
|
66
|
+
const stack = this.#stack.split("\n").slice(2).join("\n");
|
|
67
|
+
err.stack = `${err.name}: ${err.message}
|
|
68
|
+
${stack}`;
|
|
69
|
+
err.cause = errCopy;
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async stream() {
|
|
74
|
+
const res = await this.raw();
|
|
75
|
+
if (res.body == null) {
|
|
76
|
+
throw new Error("Response body is null");
|
|
77
|
+
}
|
|
78
|
+
return res.body;
|
|
79
|
+
}
|
|
80
|
+
async json() {
|
|
81
|
+
this._headers ??= {};
|
|
82
|
+
this._headers.Accept ??= "application/json";
|
|
83
|
+
const res = await this.raw();
|
|
84
|
+
return res.json();
|
|
85
|
+
}
|
|
86
|
+
async text() {
|
|
87
|
+
const res = await this.raw();
|
|
88
|
+
return res.text();
|
|
89
|
+
}
|
|
90
|
+
async arrayBuffer() {
|
|
91
|
+
this._headers ??= {};
|
|
92
|
+
this._headers.Accept ??= OCTET_STREAM_CONTENT_TYPE;
|
|
93
|
+
const res = await this.raw();
|
|
94
|
+
return res.arrayBuffer();
|
|
95
|
+
}
|
|
96
|
+
async blob() {
|
|
97
|
+
this._headers ??= {};
|
|
98
|
+
this._headers.Accept ??= OCTET_STREAM_CONTENT_TYPE;
|
|
99
|
+
const res = await this.raw();
|
|
100
|
+
return res.blob();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function _wrapMethod(method, fn) {
|
|
104
|
+
return (url, options) => {
|
|
105
|
+
return fn(url, { ...options, method });
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function createFfetch(baseOptions = {}) {
|
|
109
|
+
const captureStackTrace = baseOptions.captureStackTrace ?? true;
|
|
110
|
+
const baseFetch = baseOptions.fetch ?? fetch;
|
|
111
|
+
const wrappedFetch = baseOptions.middlewares !== void 0 && baseOptions.middlewares.length > 0 ? utils.composeMiddlewares(baseOptions.middlewares, baseFetch) : baseFetch;
|
|
112
|
+
const addons = baseOptions.addons ?? [];
|
|
113
|
+
let FfetchResultInner;
|
|
114
|
+
if (addons.length) {
|
|
115
|
+
FfetchResultInner = class extends FfetchResultImpl {
|
|
116
|
+
};
|
|
117
|
+
for (let i = 0; i < addons.length; i++) {
|
|
118
|
+
const addon = addons[i];
|
|
119
|
+
for (const key in addon.response) {
|
|
120
|
+
FfetchResultInner.prototype[key] = addon.response[key];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
FfetchResultInner = FfetchResultImpl;
|
|
125
|
+
}
|
|
126
|
+
const fn_ = (url, options = {}) => {
|
|
127
|
+
let stack;
|
|
128
|
+
if (captureStackTrace) {
|
|
129
|
+
stack = new Error().stack;
|
|
130
|
+
}
|
|
131
|
+
if (addons.length) {
|
|
132
|
+
const ctx = { url, options, baseOptions };
|
|
133
|
+
for (let i = 0; i < addons.length; i++) {
|
|
134
|
+
const addon = addons[i];
|
|
135
|
+
addon.beforeRequest?.(ctx);
|
|
136
|
+
}
|
|
137
|
+
url = ctx.url;
|
|
138
|
+
options = ctx.options;
|
|
139
|
+
}
|
|
140
|
+
let fetcher = wrappedFetch;
|
|
141
|
+
if (options.middlewares !== void 0 && options.middlewares.length > 0) {
|
|
142
|
+
fetcher = utils.composeMiddlewares(options.middlewares, wrappedFetch);
|
|
143
|
+
}
|
|
144
|
+
if (baseOptions?.baseUrl != null || options.baseUrl != null) {
|
|
145
|
+
url = new URL(url, options.baseUrl ?? baseOptions?.baseUrl).href;
|
|
146
|
+
}
|
|
147
|
+
let init;
|
|
148
|
+
let headers;
|
|
149
|
+
if (baseOptions != null) {
|
|
150
|
+
init = { ...baseOptions.extra, ...options.extra };
|
|
151
|
+
headers = { ...headersToObject(baseOptions.headers), ...headersToObject(options.headers) };
|
|
152
|
+
} else {
|
|
153
|
+
init = options.extra ?? {};
|
|
154
|
+
headers = headersToObject(options.headers);
|
|
155
|
+
}
|
|
156
|
+
if (options.json !== void 0) {
|
|
157
|
+
if (options.body != null) {
|
|
158
|
+
throw new Error("Cannot set both json and body");
|
|
159
|
+
}
|
|
160
|
+
init.body = JSON.stringify(options.json);
|
|
161
|
+
init.method = options.method ?? "POST";
|
|
162
|
+
headers["Content-Type"] ??= "application/json";
|
|
163
|
+
} else {
|
|
164
|
+
init.body = options.body;
|
|
165
|
+
init.method = options.method ?? baseOptions.method ?? "GET";
|
|
166
|
+
}
|
|
167
|
+
init.headers = headers;
|
|
168
|
+
return new FfetchResultInner(fetcher, url, init, headers, options, stack);
|
|
169
|
+
};
|
|
170
|
+
const fn = fn_;
|
|
171
|
+
fn.get = _wrapMethod("GET", fn);
|
|
172
|
+
fn.post = _wrapMethod("POST", fn);
|
|
173
|
+
fn.put = _wrapMethod("PUT", fn);
|
|
174
|
+
fn.delete = _wrapMethod("DELETE", fn);
|
|
175
|
+
fn.patch = _wrapMethod("PATCH", fn);
|
|
176
|
+
fn.head = _wrapMethod("HEAD", fn);
|
|
177
|
+
fn.options = _wrapMethod("OPTIONS", fn);
|
|
178
|
+
fn.extend = (otherOptions) => {
|
|
179
|
+
return createFfetch({
|
|
180
|
+
...baseOptions,
|
|
181
|
+
...otherOptions,
|
|
182
|
+
addons: [
|
|
183
|
+
...baseOptions.addons ?? [],
|
|
184
|
+
// eslint-disable-next-line ts/no-unsafe-assignment
|
|
185
|
+
...otherOptions.addons ?? []
|
|
186
|
+
],
|
|
187
|
+
middlewares: [
|
|
188
|
+
...baseOptions.middlewares ?? [],
|
|
189
|
+
...otherOptions.middlewares ?? []
|
|
190
|
+
],
|
|
191
|
+
headers: {
|
|
192
|
+
...baseOptions.headers,
|
|
193
|
+
...otherOptions.headers
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
return fn;
|
|
198
|
+
}
|
|
199
|
+
exports.HttpError = HttpError;
|
|
200
|
+
exports.createFfetch = createFfetch;
|
package/ffetch.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CombineAddons, FfetchMiddleware } from './_types.js';
|
|
2
|
+
import { FfetchAddon } from './addons/types.js';
|
|
3
|
+
export interface FfetchOptions {
|
|
4
|
+
/**
|
|
5
|
+
* http method
|
|
6
|
+
* @default 'GET'
|
|
7
|
+
*/
|
|
8
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | (string & {});
|
|
9
|
+
/**
|
|
10
|
+
* whether to throw HttpError on non-2xx responses
|
|
11
|
+
*
|
|
12
|
+
* when a function is provided, it will be called with the response
|
|
13
|
+
* and should return whether the response is valid.
|
|
14
|
+
* if it returns false, the response will be thrown as an HttpError
|
|
15
|
+
*
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
validateResponse?: false | ((res: Response) => boolean | Promise<boolean>);
|
|
19
|
+
/** base url to be prepended to the url */
|
|
20
|
+
baseUrl?: string;
|
|
21
|
+
/** body to be passed to fetch() */
|
|
22
|
+
body?: BodyInit;
|
|
23
|
+
/**
|
|
24
|
+
* shorthand for sending json body.
|
|
25
|
+
* mutually exclusive with `body`
|
|
26
|
+
*/
|
|
27
|
+
json?: unknown;
|
|
28
|
+
/** headers to be passed to fetch() */
|
|
29
|
+
headers?: HeadersInit;
|
|
30
|
+
/** middlewares for the requests */
|
|
31
|
+
middlewares?: FfetchMiddleware[];
|
|
32
|
+
/** any additional options to be passed to fetch() */
|
|
33
|
+
extra?: RequestInit;
|
|
34
|
+
}
|
|
35
|
+
export interface FfetchBaseOptions<Addons extends FfetchAddon<any, any>[] = FfetchAddon<any, any>[]> extends FfetchOptions {
|
|
36
|
+
/** implementation of fetch() */
|
|
37
|
+
fetch?: typeof fetch;
|
|
38
|
+
/** addons for the request */
|
|
39
|
+
addons?: Addons;
|
|
40
|
+
/**
|
|
41
|
+
* whether to capture stack trace for errors
|
|
42
|
+
* may slightly impact performance
|
|
43
|
+
*
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
captureStackTrace?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface FfetchResult extends Promise<Response> {
|
|
49
|
+
raw: () => Promise<Response>;
|
|
50
|
+
stream: () => Promise<ReadableStream<Uint8Array>>;
|
|
51
|
+
json: <T = unknown>() => Promise<T>;
|
|
52
|
+
text: () => Promise<string>;
|
|
53
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
54
|
+
blob: () => Promise<Blob>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* the main function of the library
|
|
58
|
+
*
|
|
59
|
+
* @param url url to fetch (or path, if baseUrl is set)
|
|
60
|
+
* @param params options (note that the function may mutate the object, do not rely on its immutability)
|
|
61
|
+
*/
|
|
62
|
+
export interface Ffetch<RequestMixin, ResponseMixin> {
|
|
63
|
+
(url: string, params?: FfetchOptions & RequestMixin): FfetchResult & ResponseMixin;
|
|
64
|
+
/** shorthand for making a GET request */
|
|
65
|
+
get: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
66
|
+
/** shorthand for making a POST request */
|
|
67
|
+
post: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
68
|
+
/** shorthand for making a PUT request */
|
|
69
|
+
put: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
70
|
+
/** shorthand for making a DELETE request */
|
|
71
|
+
delete: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
72
|
+
/** shorthand for making a PATCH request */
|
|
73
|
+
patch: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
74
|
+
/** shorthand for making a HEAD request */
|
|
75
|
+
head: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
76
|
+
/** shorthand for making an OPTIONS request */
|
|
77
|
+
options: (url: string, params?: FfetchOptions & RequestMixin) => FfetchResult & ResponseMixin;
|
|
78
|
+
/**
|
|
79
|
+
* extend the base options with the given options
|
|
80
|
+
*
|
|
81
|
+
* note: addons, middlewares and headers will be merged with the base options,
|
|
82
|
+
* the rest of the options will be overridden
|
|
83
|
+
*/
|
|
84
|
+
extend: <const Addons extends FfetchAddon<any, any>[], Combined extends {
|
|
85
|
+
request: object;
|
|
86
|
+
response: object;
|
|
87
|
+
} = CombineAddons<Addons>>(baseOptions: FfetchBaseOptions<Addons> & Combined['request']) => Ffetch<RequestMixin & Combined['request'], ResponseMixin & Combined['response']>;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* an error that is thrown when the response status is not 2xx,
|
|
91
|
+
* or `validateResponse` returns false
|
|
92
|
+
*/
|
|
93
|
+
export declare class HttpError extends Error {
|
|
94
|
+
readonly response: Response;
|
|
95
|
+
constructor(response: Response);
|
|
96
|
+
}
|
|
97
|
+
/** create a new ffetch function with the given base options */
|
|
98
|
+
export declare function createFfetch<const Addons extends FfetchAddon<any, any>[], Combined extends {
|
|
99
|
+
request: object;
|
|
100
|
+
response: object;
|
|
101
|
+
} = CombineAddons<Addons>>(baseOptions?: FfetchBaseOptions<Addons> & Combined['request']): Ffetch<Combined['request'], Combined['response']>;
|
package/ffetch.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { composeMiddlewares, unknownToError } from "@fuman/utils";
|
|
2
|
+
const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
|
|
3
|
+
class HttpError extends Error {
|
|
4
|
+
constructor(response) {
|
|
5
|
+
super(`HTTP Error ${response.status} ${response.statusText}`);
|
|
6
|
+
this.response = response;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function headersToObject(headers) {
|
|
10
|
+
if (!headers) return {};
|
|
11
|
+
if (Array.isArray(headers) || headers instanceof Headers) return Object.fromEntries(headers);
|
|
12
|
+
if (Symbol.iterator in headers) {
|
|
13
|
+
return Object.fromEntries(headers);
|
|
14
|
+
}
|
|
15
|
+
return headers;
|
|
16
|
+
}
|
|
17
|
+
class FfetchResultImpl {
|
|
18
|
+
#fetch;
|
|
19
|
+
_url;
|
|
20
|
+
_init;
|
|
21
|
+
_options;
|
|
22
|
+
_headers;
|
|
23
|
+
#stack;
|
|
24
|
+
constructor(fetch2, url, init, headers, options, stack) {
|
|
25
|
+
this.#fetch = fetch2;
|
|
26
|
+
this._init = init;
|
|
27
|
+
this._url = url;
|
|
28
|
+
this._options = options;
|
|
29
|
+
this._headers = headers;
|
|
30
|
+
this.#stack = stack;
|
|
31
|
+
}
|
|
32
|
+
then(onfulfilled, onrejected) {
|
|
33
|
+
return this.raw().then(onfulfilled, onrejected);
|
|
34
|
+
}
|
|
35
|
+
catch(onrejected) {
|
|
36
|
+
return this.raw().catch(onrejected);
|
|
37
|
+
}
|
|
38
|
+
finally(onfinally) {
|
|
39
|
+
return this.raw().finally(onfinally);
|
|
40
|
+
}
|
|
41
|
+
get [Symbol.toStringTag]() {
|
|
42
|
+
return "FfetchResult";
|
|
43
|
+
}
|
|
44
|
+
async #fetchAndValidate() {
|
|
45
|
+
const res = await this.#fetch(new Request(this._url, this._init));
|
|
46
|
+
if (this._options.validateResponse === void 0 || this._options.validateResponse !== false) {
|
|
47
|
+
if (typeof this._options.validateResponse === "function") {
|
|
48
|
+
if (!await this._options.validateResponse(res)) {
|
|
49
|
+
throw new HttpError(res);
|
|
50
|
+
}
|
|
51
|
+
} else if (!res.ok) {
|
|
52
|
+
throw new HttpError(res);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
57
|
+
async raw() {
|
|
58
|
+
if (this.#stack == null) return this.#fetchAndValidate();
|
|
59
|
+
try {
|
|
60
|
+
return await this.#fetchAndValidate();
|
|
61
|
+
} catch (err_) {
|
|
62
|
+
const err = unknownToError(err_);
|
|
63
|
+
const errCopy = structuredClone(err_);
|
|
64
|
+
const stack = this.#stack.split("\n").slice(2).join("\n");
|
|
65
|
+
err.stack = `${err.name}: ${err.message}
|
|
66
|
+
${stack}`;
|
|
67
|
+
err.cause = errCopy;
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async stream() {
|
|
72
|
+
const res = await this.raw();
|
|
73
|
+
if (res.body == null) {
|
|
74
|
+
throw new Error("Response body is null");
|
|
75
|
+
}
|
|
76
|
+
return res.body;
|
|
77
|
+
}
|
|
78
|
+
async json() {
|
|
79
|
+
this._headers ??= {};
|
|
80
|
+
this._headers.Accept ??= "application/json";
|
|
81
|
+
const res = await this.raw();
|
|
82
|
+
return res.json();
|
|
83
|
+
}
|
|
84
|
+
async text() {
|
|
85
|
+
const res = await this.raw();
|
|
86
|
+
return res.text();
|
|
87
|
+
}
|
|
88
|
+
async arrayBuffer() {
|
|
89
|
+
this._headers ??= {};
|
|
90
|
+
this._headers.Accept ??= OCTET_STREAM_CONTENT_TYPE;
|
|
91
|
+
const res = await this.raw();
|
|
92
|
+
return res.arrayBuffer();
|
|
93
|
+
}
|
|
94
|
+
async blob() {
|
|
95
|
+
this._headers ??= {};
|
|
96
|
+
this._headers.Accept ??= OCTET_STREAM_CONTENT_TYPE;
|
|
97
|
+
const res = await this.raw();
|
|
98
|
+
return res.blob();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function _wrapMethod(method, fn) {
|
|
102
|
+
return (url, options) => {
|
|
103
|
+
return fn(url, { ...options, method });
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function createFfetch(baseOptions = {}) {
|
|
107
|
+
const captureStackTrace = baseOptions.captureStackTrace ?? true;
|
|
108
|
+
const baseFetch = baseOptions.fetch ?? fetch;
|
|
109
|
+
const wrappedFetch = baseOptions.middlewares !== void 0 && baseOptions.middlewares.length > 0 ? composeMiddlewares(baseOptions.middlewares, baseFetch) : baseFetch;
|
|
110
|
+
const addons = baseOptions.addons ?? [];
|
|
111
|
+
let FfetchResultInner;
|
|
112
|
+
if (addons.length) {
|
|
113
|
+
FfetchResultInner = class extends FfetchResultImpl {
|
|
114
|
+
};
|
|
115
|
+
for (let i = 0; i < addons.length; i++) {
|
|
116
|
+
const addon = addons[i];
|
|
117
|
+
for (const key in addon.response) {
|
|
118
|
+
FfetchResultInner.prototype[key] = addon.response[key];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
FfetchResultInner = FfetchResultImpl;
|
|
123
|
+
}
|
|
124
|
+
const fn_ = (url, options = {}) => {
|
|
125
|
+
let stack;
|
|
126
|
+
if (captureStackTrace) {
|
|
127
|
+
stack = new Error().stack;
|
|
128
|
+
}
|
|
129
|
+
if (addons.length) {
|
|
130
|
+
const ctx = { url, options, baseOptions };
|
|
131
|
+
for (let i = 0; i < addons.length; i++) {
|
|
132
|
+
const addon = addons[i];
|
|
133
|
+
addon.beforeRequest?.(ctx);
|
|
134
|
+
}
|
|
135
|
+
url = ctx.url;
|
|
136
|
+
options = ctx.options;
|
|
137
|
+
}
|
|
138
|
+
let fetcher = wrappedFetch;
|
|
139
|
+
if (options.middlewares !== void 0 && options.middlewares.length > 0) {
|
|
140
|
+
fetcher = composeMiddlewares(options.middlewares, wrappedFetch);
|
|
141
|
+
}
|
|
142
|
+
if (baseOptions?.baseUrl != null || options.baseUrl != null) {
|
|
143
|
+
url = new URL(url, options.baseUrl ?? baseOptions?.baseUrl).href;
|
|
144
|
+
}
|
|
145
|
+
let init;
|
|
146
|
+
let headers;
|
|
147
|
+
if (baseOptions != null) {
|
|
148
|
+
init = { ...baseOptions.extra, ...options.extra };
|
|
149
|
+
headers = { ...headersToObject(baseOptions.headers), ...headersToObject(options.headers) };
|
|
150
|
+
} else {
|
|
151
|
+
init = options.extra ?? {};
|
|
152
|
+
headers = headersToObject(options.headers);
|
|
153
|
+
}
|
|
154
|
+
if (options.json !== void 0) {
|
|
155
|
+
if (options.body != null) {
|
|
156
|
+
throw new Error("Cannot set both json and body");
|
|
157
|
+
}
|
|
158
|
+
init.body = JSON.stringify(options.json);
|
|
159
|
+
init.method = options.method ?? "POST";
|
|
160
|
+
headers["Content-Type"] ??= "application/json";
|
|
161
|
+
} else {
|
|
162
|
+
init.body = options.body;
|
|
163
|
+
init.method = options.method ?? baseOptions.method ?? "GET";
|
|
164
|
+
}
|
|
165
|
+
init.headers = headers;
|
|
166
|
+
return new FfetchResultInner(fetcher, url, init, headers, options, stack);
|
|
167
|
+
};
|
|
168
|
+
const fn = fn_;
|
|
169
|
+
fn.get = _wrapMethod("GET", fn);
|
|
170
|
+
fn.post = _wrapMethod("POST", fn);
|
|
171
|
+
fn.put = _wrapMethod("PUT", fn);
|
|
172
|
+
fn.delete = _wrapMethod("DELETE", fn);
|
|
173
|
+
fn.patch = _wrapMethod("PATCH", fn);
|
|
174
|
+
fn.head = _wrapMethod("HEAD", fn);
|
|
175
|
+
fn.options = _wrapMethod("OPTIONS", fn);
|
|
176
|
+
fn.extend = (otherOptions) => {
|
|
177
|
+
return createFfetch({
|
|
178
|
+
...baseOptions,
|
|
179
|
+
...otherOptions,
|
|
180
|
+
addons: [
|
|
181
|
+
...baseOptions.addons ?? [],
|
|
182
|
+
// eslint-disable-next-line ts/no-unsafe-assignment
|
|
183
|
+
...otherOptions.addons ?? []
|
|
184
|
+
],
|
|
185
|
+
middlewares: [
|
|
186
|
+
...baseOptions.middlewares ?? [],
|
|
187
|
+
...otherOptions.middlewares ?? []
|
|
188
|
+
],
|
|
189
|
+
headers: {
|
|
190
|
+
...baseOptions.headers,
|
|
191
|
+
...otherOptions.headers
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
return fn;
|
|
196
|
+
}
|
|
197
|
+
export {
|
|
198
|
+
HttpError,
|
|
199
|
+
createFfetch
|
|
200
|
+
};
|
package/index.cjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const _default = require("./default.cjs");
|
|
4
|
+
const ffetch = require("./ffetch.cjs");
|
|
5
|
+
const bundle = require("./addons/bundle.cjs");
|
|
6
|
+
exports.ffetchBase = _default.ffetchBase;
|
|
7
|
+
exports.ffetchDefaultAddons = _default.ffetchDefaultAddons;
|
|
8
|
+
exports.HttpError = ffetch.HttpError;
|
|
9
|
+
exports.createFfetch = ffetch.createFfetch;
|
|
10
|
+
exports.ffetchAddons = bundle;
|
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ffetchBase, ffetchDefaultAddons } from "./default.js";
|
|
2
|
+
import { HttpError, createFfetch } from "./ffetch.js";
|
|
3
|
+
import * as bundle from "./addons/bundle.js";
|
|
4
|
+
export {
|
|
5
|
+
HttpError,
|
|
6
|
+
createFfetch,
|
|
7
|
+
bundle as ffetchAddons,
|
|
8
|
+
ffetchBase,
|
|
9
|
+
ffetchDefaultAddons
|
|
10
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fuman/fetch",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "tiny wrapper over fetch",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@fuman/utils": "^0.0.1"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"tough-cookie": "^5.0.0 || ^4.0.0",
|
|
12
|
+
"valibot": "^0.42.0",
|
|
13
|
+
"yup": "^1.0.0",
|
|
14
|
+
"zod": "^3.0.0"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./index.d.ts",
|
|
20
|
+
"default": "./index.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./index.d.cts",
|
|
24
|
+
"default": "./index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./zod": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./zod.d.ts",
|
|
30
|
+
"default": "./zod.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./zod.d.cts",
|
|
34
|
+
"default": "./zod.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"./valibot": {
|
|
38
|
+
"import": {
|
|
39
|
+
"types": "./valibot.d.ts",
|
|
40
|
+
"default": "./valibot.js"
|
|
41
|
+
},
|
|
42
|
+
"require": {
|
|
43
|
+
"types": "./valibot.d.cts",
|
|
44
|
+
"default": "./valibot.cjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./yup": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./yup.d.ts",
|
|
50
|
+
"default": "./yup.js"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./yup.d.cts",
|
|
54
|
+
"default": "./yup.cjs"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./tough": {
|
|
58
|
+
"import": {
|
|
59
|
+
"types": "./tough.d.ts",
|
|
60
|
+
"default": "./tough.js"
|
|
61
|
+
},
|
|
62
|
+
"require": {
|
|
63
|
+
"types": "./tough.d.cts",
|
|
64
|
+
"default": "./tough.cjs"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"sideEffects": false,
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"tough-cookie": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"valibot": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"yup": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"zod": {
|
|
80
|
+
"optional": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"author": "",
|
|
84
|
+
"repository": {
|
|
85
|
+
"type": "git",
|
|
86
|
+
"url": "git+https://github.com/teidesu/fuman.git"
|
|
87
|
+
},
|
|
88
|
+
"scripts": {}
|
|
89
|
+
}
|
package/tough.cjs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function cookieJarMiddleware(jar) {
|
|
4
|
+
return async (ctx, next) => {
|
|
5
|
+
ctx.headers.append("Cookie", await jar.getCookieString(ctx.url));
|
|
6
|
+
const res = await next(ctx);
|
|
7
|
+
for (const header of res.headers.getSetCookie()) {
|
|
8
|
+
await jar.setCookie(header, res.url);
|
|
9
|
+
}
|
|
10
|
+
return res;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function toughCookieAddon() {
|
|
14
|
+
return {
|
|
15
|
+
beforeRequest(ctx) {
|
|
16
|
+
if (ctx.options.cookies != null || ctx.baseOptions.cookies != null) {
|
|
17
|
+
const jar = ctx.options.cookies ?? ctx.baseOptions.cookies;
|
|
18
|
+
ctx.options.middlewares ??= [];
|
|
19
|
+
ctx.options.middlewares.push(cookieJarMiddleware(jar));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
exports.toughCookieAddon = toughCookieAddon;
|
package/tough.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./addons/tough-cookie.js"
|
package/tough.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
function cookieJarMiddleware(jar) {
|
|
2
|
+
return async (ctx, next) => {
|
|
3
|
+
ctx.headers.append("Cookie", await jar.getCookieString(ctx.url));
|
|
4
|
+
const res = await next(ctx);
|
|
5
|
+
for (const header of res.headers.getSetCookie()) {
|
|
6
|
+
await jar.setCookie(header, res.url);
|
|
7
|
+
}
|
|
8
|
+
return res;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function toughCookieAddon() {
|
|
12
|
+
return {
|
|
13
|
+
beforeRequest(ctx) {
|
|
14
|
+
if (ctx.options.cookies != null || ctx.baseOptions.cookies != null) {
|
|
15
|
+
const jar = ctx.options.cookies ?? ctx.baseOptions.cookies;
|
|
16
|
+
ctx.options.middlewares ??= [];
|
|
17
|
+
ctx.options.middlewares.push(cookieJarMiddleware(jar));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
toughCookieAddon
|
|
24
|
+
};
|
package/valibot.cjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const valibot = require("valibot");
|
|
4
|
+
function ffetchValibotAdapter({ async, ...rest } = {}) {
|
|
5
|
+
const _provider = null;
|
|
6
|
+
const parser = async ? async function(schema, value) {
|
|
7
|
+
return valibot.parseAsync(schema, value, rest);
|
|
8
|
+
} : function(schema, value) {
|
|
9
|
+
return valibot.parse(schema, value, rest);
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
_provider,
|
|
13
|
+
parse: parser
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
exports.ffetchValibotAdapter = ffetchValibotAdapter;
|
package/valibot.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./addons/parse/adapters/valibot.js"
|