@nickyzj2023/utils 1.0.5 → 1.0.7
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/package.json +2 -3
- package/src/network.ts +100 -100
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nickyzj2023/utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"docs": "typedoc src/index.ts",
|
|
9
|
-
"build": "bun build --target=bun --outdir ./dist --minify ./src/index.ts && tsc && bun run docs"
|
|
10
|
-
"publish": "npm version patch && npm publish"
|
|
9
|
+
"build": "bun build --target=bun --outdir ./dist --minify ./src/index.ts && tsc && bun run docs"
|
|
11
10
|
},
|
|
12
11
|
"devDependencies": {
|
|
13
12
|
"@types/bun": "latest",
|
package/src/network.ts
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
import { isObject } from "./is";
|
|
2
|
-
import LRUCache from "./lru-cache";
|
|
3
|
-
|
|
4
|
-
const cachedRequests = new LRUCache<string, Promise<Response>>();
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 基于 Fetch API 的请求客户端
|
|
8
|
-
* @param baseURL 接口前缀,如 https://nickyzj.run:3030,也可以不填
|
|
9
|
-
*
|
|
10
|
-
* @remarks
|
|
11
|
-
* 特性:
|
|
12
|
-
* - 在 body 里直接传递对象
|
|
13
|
-
* - 能够缓存 GET 请求
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* // 用法1:创建客户端
|
|
17
|
-
* const api = fetcher("https://nickyzj.run:3030");
|
|
18
|
-
* const res = await api.get<Blog>("/blogs/hello-world");
|
|
19
|
-
*
|
|
20
|
-
* // 用法2:直接发送请求
|
|
21
|
-
* const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world");
|
|
22
|
-
*/
|
|
23
|
-
export const fetcher = (baseURL = "") => {
|
|
24
|
-
const createRequest = async <T>(path: string, options: RequestInit = {}) => {
|
|
25
|
-
// 构建完整 URL
|
|
26
|
-
const url = baseURL ? `${baseURL}${path}` : path;
|
|
27
|
-
|
|
28
|
-
// 处理 body 为对象的情况
|
|
29
|
-
if (isObject(options.body)) {
|
|
30
|
-
options.body = JSON.stringify(options.body);
|
|
31
|
-
options.headers = {
|
|
32
|
-
...options.headers,
|
|
33
|
-
"Content-Type": "application/json",
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const request = () => fetch(url, options);
|
|
38
|
-
let promise: Promise<Response>;
|
|
39
|
-
|
|
40
|
-
const canCache = options.method === "GET" || !options.method;
|
|
41
|
-
if (!canCache) {
|
|
42
|
-
promise = request();
|
|
43
|
-
} else {
|
|
44
|
-
let tempPromise = cachedRequests.get(url);
|
|
45
|
-
if (!tempPromise) {
|
|
46
|
-
tempPromise = request();
|
|
47
|
-
cachedRequests.set(url, tempPromise);
|
|
48
|
-
}
|
|
49
|
-
promise = tempPromise;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 必须使用 clone() 消费一个新的响应体,否则下次从 cache 中获取的响应体会报错(无法被重复消费)
|
|
53
|
-
const response = (await promise).clone();
|
|
54
|
-
if (!response.ok) {
|
|
55
|
-
throw new Error(response.statusText);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const data = await response.json();
|
|
59
|
-
return data as T;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
get: <T>(url: string, options: Omit<RequestInit, "method"> = {}) =>
|
|
64
|
-
createRequest<T>(url, { ...options, method: "GET" }),
|
|
65
|
-
|
|
66
|
-
post: <T>(
|
|
67
|
-
url: string,
|
|
68
|
-
body?: any,
|
|
69
|
-
options: Omit<RequestInit, "method" | "body"> = {},
|
|
70
|
-
) => createRequest<T>(url, { ...options, method: "POST", body }),
|
|
71
|
-
|
|
72
|
-
put: <T>(
|
|
73
|
-
url: string,
|
|
74
|
-
body?: any,
|
|
75
|
-
options: Omit<RequestInit, "method" | "body"> = {},
|
|
76
|
-
) => createRequest<T>(url, { ...options, method: "PUT", body }),
|
|
77
|
-
|
|
78
|
-
delete: <T>(url: string, options: Omit<RequestInit, "method"> = {}) =>
|
|
79
|
-
createRequest<T>(url, { ...options, method: "DELETE" }),
|
|
80
|
-
};
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Go 语言风格的异步处理方式
|
|
85
|
-
* @param promise 一个能被 await 的异步函数
|
|
86
|
-
* @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
|
|
87
|
-
*
|
|
88
|
-
* @example
|
|
89
|
-
* const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
|
|
90
|
-
*/
|
|
91
|
-
export const to = async <T, Error>(
|
|
92
|
-
promise: Promise<T>,
|
|
93
|
-
): Promise<[null, T] | [
|
|
94
|
-
try {
|
|
95
|
-
const response = await promise;
|
|
96
|
-
return [null, response];
|
|
97
|
-
} catch (error) {
|
|
98
|
-
return [error as
|
|
99
|
-
}
|
|
100
|
-
};
|
|
1
|
+
import { isObject } from "./is";
|
|
2
|
+
import LRUCache from "./lru-cache";
|
|
3
|
+
|
|
4
|
+
const cachedRequests = new LRUCache<string, Promise<Response>>();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 基于 Fetch API 的请求客户端
|
|
8
|
+
* @param baseURL 接口前缀,如 https://nickyzj.run:3030,也可以不填
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* 特性:
|
|
12
|
+
* - 在 body 里直接传递对象
|
|
13
|
+
* - 能够缓存 GET 请求
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // 用法1:创建客户端
|
|
17
|
+
* const api = fetcher("https://nickyzj.run:3030");
|
|
18
|
+
* const res = await api.get<Blog>("/blogs/hello-world");
|
|
19
|
+
*
|
|
20
|
+
* // 用法2:直接发送请求
|
|
21
|
+
* const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world");
|
|
22
|
+
*/
|
|
23
|
+
export const fetcher = (baseURL = "") => {
|
|
24
|
+
const createRequest = async <T>(path: string, options: RequestInit = {}) => {
|
|
25
|
+
// 构建完整 URL
|
|
26
|
+
const url = baseURL ? `${baseURL}${path}` : path;
|
|
27
|
+
|
|
28
|
+
// 处理 body 为对象的情况
|
|
29
|
+
if (isObject(options.body)) {
|
|
30
|
+
options.body = JSON.stringify(options.body);
|
|
31
|
+
options.headers = {
|
|
32
|
+
...options.headers,
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const request = () => fetch(url, options);
|
|
38
|
+
let promise: Promise<Response>;
|
|
39
|
+
|
|
40
|
+
const canCache = options.method === "GET" || !options.method;
|
|
41
|
+
if (!canCache) {
|
|
42
|
+
promise = request();
|
|
43
|
+
} else {
|
|
44
|
+
let tempPromise = cachedRequests.get(url);
|
|
45
|
+
if (!tempPromise) {
|
|
46
|
+
tempPromise = request();
|
|
47
|
+
cachedRequests.set(url, tempPromise);
|
|
48
|
+
}
|
|
49
|
+
promise = tempPromise;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 必须使用 clone() 消费一个新的响应体,否则下次从 cache 中获取的响应体会报错(无法被重复消费)
|
|
53
|
+
const response = (await promise).clone();
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error(response.statusText);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const data = await response.json();
|
|
59
|
+
return data as T;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
get: <T>(url: string, options: Omit<RequestInit, "method"> = {}) =>
|
|
64
|
+
createRequest<T>(url, { ...options, method: "GET" }),
|
|
65
|
+
|
|
66
|
+
post: <T>(
|
|
67
|
+
url: string,
|
|
68
|
+
body?: any,
|
|
69
|
+
options: Omit<RequestInit, "method" | "body"> = {},
|
|
70
|
+
) => createRequest<T>(url, { ...options, method: "POST", body }),
|
|
71
|
+
|
|
72
|
+
put: <T>(
|
|
73
|
+
url: string,
|
|
74
|
+
body?: any,
|
|
75
|
+
options: Omit<RequestInit, "method" | "body"> = {},
|
|
76
|
+
) => createRequest<T>(url, { ...options, method: "PUT", body }),
|
|
77
|
+
|
|
78
|
+
delete: <T>(url: string, options: Omit<RequestInit, "method"> = {}) =>
|
|
79
|
+
createRequest<T>(url, { ...options, method: "DELETE" }),
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Go 语言风格的异步处理方式
|
|
85
|
+
* @param promise 一个能被 await 的异步函数
|
|
86
|
+
* @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
|
|
90
|
+
*/
|
|
91
|
+
export const to = async <T, U = Error>(
|
|
92
|
+
promise: Promise<T>,
|
|
93
|
+
): Promise<[null, T] | [U, undefined]> => {
|
|
94
|
+
try {
|
|
95
|
+
const response = await promise;
|
|
96
|
+
return [null, response];
|
|
97
|
+
} catch (error) {
|
|
98
|
+
return [error as U, undefined];
|
|
99
|
+
}
|
|
100
|
+
};
|