@yh-ui/request 0.1.21
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 +21 -0
- package/README.md +274 -0
- package/dist/adapters/fetch.cjs +157 -0
- package/dist/adapters/fetch.d.ts +25 -0
- package/dist/adapters/fetch.mjs +148 -0
- package/dist/adapters/index.cjs +27 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.mjs +2 -0
- package/dist/adapters/platform.cjs +394 -0
- package/dist/adapters/platform.d.ts +72 -0
- package/dist/adapters/platform.mjs +369 -0
- package/dist/cache/index.cjs +56 -0
- package/dist/cache/index.d.ts +21 -0
- package/dist/cache/index.mjs +14 -0
- package/dist/cache/indexedDB.cjs +188 -0
- package/dist/cache/indexedDB.d.ts +58 -0
- package/dist/cache/indexedDB.mjs +176 -0
- package/dist/cache/localStorage.cjs +158 -0
- package/dist/cache/localStorage.d.ts +58 -0
- package/dist/cache/localStorage.mjs +153 -0
- package/dist/cache/memory.cjs +112 -0
- package/dist/cache/memory.d.ts +71 -0
- package/dist/cache/memory.mjs +103 -0
- package/dist/graphql.cjs +255 -0
- package/dist/graphql.d.ts +192 -0
- package/dist/graphql.mjs +235 -0
- package/dist/http-cache.cjs +248 -0
- package/dist/http-cache.d.ts +156 -0
- package/dist/http-cache.mjs +233 -0
- package/dist/index.cjs +181 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.mjs +16 -0
- package/dist/interceptors/debug.cjs +139 -0
- package/dist/interceptors/debug.d.ts +92 -0
- package/dist/interceptors/debug.mjs +130 -0
- package/dist/interceptors/index.cjs +38 -0
- package/dist/interceptors/index.d.ts +6 -0
- package/dist/interceptors/index.mjs +3 -0
- package/dist/interceptors/progress.cjs +185 -0
- package/dist/interceptors/progress.d.ts +97 -0
- package/dist/interceptors/progress.mjs +177 -0
- package/dist/interceptors/security.cjs +154 -0
- package/dist/interceptors/security.d.ts +83 -0
- package/dist/interceptors/security.mjs +134 -0
- package/dist/plugin.cjs +166 -0
- package/dist/plugin.d.ts +106 -0
- package/dist/plugin.mjs +163 -0
- package/dist/request.cjs +396 -0
- package/dist/request.d.ts +111 -0
- package/dist/request.mjs +339 -0
- package/dist/types.cjs +13 -0
- package/dist/types.d.ts +157 -0
- package/dist/types.mjs +7 -0
- package/dist/useAIStream.cjs +125 -0
- package/dist/useAIStream.d.ts +89 -0
- package/dist/useAIStream.mjs +108 -0
- package/dist/useLoadMore.cjs +136 -0
- package/dist/useLoadMore.d.ts +84 -0
- package/dist/useLoadMore.mjs +134 -0
- package/dist/usePagination.cjs +141 -0
- package/dist/usePagination.d.ts +89 -0
- package/dist/usePagination.mjs +132 -0
- package/dist/useQueue.cjs +243 -0
- package/dist/useQueue.d.ts +118 -0
- package/dist/useQueue.mjs +239 -0
- package/dist/useRequest.cjs +325 -0
- package/dist/useRequest.d.ts +126 -0
- package/dist/useRequest.mjs +329 -0
- package/dist/useRequestQueue.cjs +36 -0
- package/dist/useRequestQueue.d.ts +52 -0
- package/dist/useRequestQueue.mjs +27 -0
- package/dist/useSSE.cjs +241 -0
- package/dist/useSSE.d.ts +74 -0
- package/dist/useSSE.mjs +226 -0
- package/dist/websocket.cjs +325 -0
- package/dist/websocket.d.ts +163 -0
- package/dist/websocket.mjs +316 -0
- package/package.json +61 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createCSRFInterceptor = createCSRFInterceptor;
|
|
7
|
+
exports.createSecurityInterceptor = createSecurityInterceptor;
|
|
8
|
+
exports.createTokenRefreshInterceptor = createTokenRefreshInterceptor;
|
|
9
|
+
function createCSRFInterceptor(config = {}) {
|
|
10
|
+
const {
|
|
11
|
+
cookieName = "XSRF-TOKEN",
|
|
12
|
+
headerName = "X-XSRF-TOKEN",
|
|
13
|
+
getToken
|
|
14
|
+
} = config;
|
|
15
|
+
const getCSRFToken = () => {
|
|
16
|
+
if (getToken) {
|
|
17
|
+
return getToken();
|
|
18
|
+
}
|
|
19
|
+
if (typeof document === "undefined") return void 0;
|
|
20
|
+
const cookies = document.cookie.split(";");
|
|
21
|
+
for (const cookie of cookies) {
|
|
22
|
+
const [name, value] = cookie.trim().split("=");
|
|
23
|
+
if (name === cookieName) {
|
|
24
|
+
return decodeURIComponent(value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return void 0;
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
/**
|
|
31
|
+
* 请求拦截 - 添加 CSRF Token
|
|
32
|
+
*/
|
|
33
|
+
onRequest: config2 => {
|
|
34
|
+
const safeMethods = ["GET", "HEAD", "OPTIONS"];
|
|
35
|
+
if (!safeMethods.includes(config2.method || "GET")) {
|
|
36
|
+
const token = getCSRFToken();
|
|
37
|
+
if (token) {
|
|
38
|
+
return {
|
|
39
|
+
...config2,
|
|
40
|
+
headers: {
|
|
41
|
+
...config2.headers,
|
|
42
|
+
[headerName]: token
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return config2;
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* 获取 CSRF Token
|
|
51
|
+
*/
|
|
52
|
+
getCSRFToken
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function createTokenRefreshInterceptor(config = {}) {
|
|
56
|
+
const {
|
|
57
|
+
statusCode = 401,
|
|
58
|
+
refreshToken,
|
|
59
|
+
isRefreshing = () => false,
|
|
60
|
+
pendingRequests = [],
|
|
61
|
+
updateHeaders,
|
|
62
|
+
retryTimes = 3
|
|
63
|
+
} = config;
|
|
64
|
+
const originalConfigs = /* @__PURE__ */new Map();
|
|
65
|
+
let currentRetryTimes = retryTimes;
|
|
66
|
+
return {
|
|
67
|
+
/**
|
|
68
|
+
* 请求拦截
|
|
69
|
+
*/
|
|
70
|
+
onRequest: config2 => {
|
|
71
|
+
originalConfigs.set(config2.requestId, config2);
|
|
72
|
+
return config2;
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* 响应拦截 - 处理 401
|
|
76
|
+
*/
|
|
77
|
+
onResponseError: async (error, _request) => {
|
|
78
|
+
const {
|
|
79
|
+
response,
|
|
80
|
+
config: errorConfig
|
|
81
|
+
} = error;
|
|
82
|
+
if (response?.status !== statusCode) {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (currentRetryTimes <= 0) {
|
|
86
|
+
currentRetryTimes = retryTimes;
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
const config2 = errorConfig;
|
|
90
|
+
if (!config2) {
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
if (isRefreshing()) {
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
pendingRequests.push(() => {
|
|
96
|
+
_request(config2).then(resolve).catch(reject);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (refreshToken) {
|
|
101
|
+
const refreshed = await refreshToken();
|
|
102
|
+
if (refreshed) {
|
|
103
|
+
if (updateHeaders && config2.headers) {
|
|
104
|
+
const newHeaders = {
|
|
105
|
+
...config2.headers
|
|
106
|
+
};
|
|
107
|
+
updateHeaders(newHeaders);
|
|
108
|
+
config2.headers = newHeaders;
|
|
109
|
+
}
|
|
110
|
+
currentRetryTimes--;
|
|
111
|
+
return _request(config2);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
},
|
|
116
|
+
/**
|
|
117
|
+
* 重置重试次数
|
|
118
|
+
*/
|
|
119
|
+
resetRetryTimes: () => {
|
|
120
|
+
currentRetryTimes = retryTimes;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function createSecurityInterceptor(options = {}) {
|
|
125
|
+
const {
|
|
126
|
+
csrf = {},
|
|
127
|
+
tokenRefresh = {}
|
|
128
|
+
} = options;
|
|
129
|
+
const csrfInterceptor = csrf === false ? null : createCSRFInterceptor(csrf);
|
|
130
|
+
const tokenRefreshInterceptor = tokenRefresh === false ? null : createTokenRefreshInterceptor(tokenRefresh);
|
|
131
|
+
return {
|
|
132
|
+
/**
|
|
133
|
+
* 请求拦截
|
|
134
|
+
*/
|
|
135
|
+
onRequest: config => {
|
|
136
|
+
let result = config;
|
|
137
|
+
if (csrfInterceptor) {
|
|
138
|
+
result = csrfInterceptor.onRequest(result);
|
|
139
|
+
}
|
|
140
|
+
if (tokenRefreshInterceptor) {
|
|
141
|
+
result = tokenRefreshInterceptor.onRequest(result);
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
},
|
|
145
|
+
/**
|
|
146
|
+
* 获取 CSRF Token
|
|
147
|
+
*/
|
|
148
|
+
getCSRFToken: csrfInterceptor?.getCSRFToken,
|
|
149
|
+
/**
|
|
150
|
+
* 重置 Token 刷新状态
|
|
151
|
+
*/
|
|
152
|
+
resetTokenRefresh: tokenRefreshInterceptor?.resetRetryTimes
|
|
153
|
+
};
|
|
154
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安全拦截器
|
|
3
|
+
* 包含 CSRF 防护和 Token 刷新功能
|
|
4
|
+
*/
|
|
5
|
+
import type { InternalRequestOptions, RequestResponse, RequestError } from '../types';
|
|
6
|
+
/** CSRF 配置 */
|
|
7
|
+
export interface CSRFConfig {
|
|
8
|
+
/** CSRF Token Cookie 名称 */
|
|
9
|
+
cookieName?: string;
|
|
10
|
+
/** CSRF Token Header 名称 */
|
|
11
|
+
headerName?: string;
|
|
12
|
+
/** 获取 Token 的函数 */
|
|
13
|
+
getToken?: () => string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Token 刷新配置 */
|
|
16
|
+
export interface TokenRefreshConfig {
|
|
17
|
+
/** 401 状态码是否触发刷新 */
|
|
18
|
+
statusCode?: number;
|
|
19
|
+
/** 刷新 Token 的函数 */
|
|
20
|
+
refreshToken?: () => Promise<boolean>;
|
|
21
|
+
/** 是否正在刷新中 */
|
|
22
|
+
isRefreshing?: () => boolean;
|
|
23
|
+
/** 等待刷新的请求队列 */
|
|
24
|
+
pendingRequests?: Array<() => void>;
|
|
25
|
+
/** 刷新后的 Header 更新 */
|
|
26
|
+
updateHeaders?: (headers: Record<string, string>) => void;
|
|
27
|
+
/** 重试次数 */
|
|
28
|
+
retryTimes?: number;
|
|
29
|
+
}
|
|
30
|
+
/** 安全拦截器选项 */
|
|
31
|
+
export interface SecurityInterceptorOptions {
|
|
32
|
+
/** CSRF 配置 */
|
|
33
|
+
csrf?: CSRFConfig | false;
|
|
34
|
+
/** Token 刷新配置 */
|
|
35
|
+
tokenRefresh?: TokenRefreshConfig | false;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 创建 CSRF 拦截器
|
|
39
|
+
*/
|
|
40
|
+
export declare function createCSRFInterceptor(config?: CSRFConfig): {
|
|
41
|
+
/**
|
|
42
|
+
* 请求拦截 - 添加 CSRF Token
|
|
43
|
+
*/
|
|
44
|
+
onRequest: (config: InternalRequestOptions) => InternalRequestOptions;
|
|
45
|
+
/**
|
|
46
|
+
* 获取 CSRF Token
|
|
47
|
+
*/
|
|
48
|
+
getCSRFToken: () => string | undefined;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* 创建 Token 刷新拦截器
|
|
52
|
+
*/
|
|
53
|
+
export declare function createTokenRefreshInterceptor(config?: TokenRefreshConfig): {
|
|
54
|
+
/**
|
|
55
|
+
* 请求拦截
|
|
56
|
+
*/
|
|
57
|
+
onRequest: (config: InternalRequestOptions) => InternalRequestOptions;
|
|
58
|
+
/**
|
|
59
|
+
* 响应拦截 - 处理 401
|
|
60
|
+
*/
|
|
61
|
+
onResponseError: (error: RequestError, _request: (config: InternalRequestOptions) => Promise<RequestResponse>) => Promise<RequestResponse>;
|
|
62
|
+
/**
|
|
63
|
+
* 重置重试次数
|
|
64
|
+
*/
|
|
65
|
+
resetRetryTimes: () => void;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* 创建安全拦截器
|
|
69
|
+
*/
|
|
70
|
+
export declare function createSecurityInterceptor(options?: SecurityInterceptorOptions): {
|
|
71
|
+
/**
|
|
72
|
+
* 请求拦截
|
|
73
|
+
*/
|
|
74
|
+
onRequest: (config: InternalRequestOptions) => InternalRequestOptions;
|
|
75
|
+
/**
|
|
76
|
+
* 获取 CSRF Token
|
|
77
|
+
*/
|
|
78
|
+
getCSRFToken: (() => string | undefined) | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* 重置 Token 刷新状态
|
|
81
|
+
*/
|
|
82
|
+
resetTokenRefresh: (() => void) | undefined;
|
|
83
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export function createCSRFInterceptor(config = {}) {
|
|
2
|
+
const { cookieName = "XSRF-TOKEN", headerName = "X-XSRF-TOKEN", getToken } = config;
|
|
3
|
+
const getCSRFToken = () => {
|
|
4
|
+
if (getToken) {
|
|
5
|
+
return getToken();
|
|
6
|
+
}
|
|
7
|
+
if (typeof document === "undefined") return void 0;
|
|
8
|
+
const cookies = document.cookie.split(";");
|
|
9
|
+
for (const cookie of cookies) {
|
|
10
|
+
const [name, value] = cookie.trim().split("=");
|
|
11
|
+
if (name === cookieName) {
|
|
12
|
+
return decodeURIComponent(value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return void 0;
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* 请求拦截 - 添加 CSRF Token
|
|
20
|
+
*/
|
|
21
|
+
onRequest: (config2) => {
|
|
22
|
+
const safeMethods = ["GET", "HEAD", "OPTIONS"];
|
|
23
|
+
if (!safeMethods.includes(config2.method || "GET")) {
|
|
24
|
+
const token = getCSRFToken();
|
|
25
|
+
if (token) {
|
|
26
|
+
return {
|
|
27
|
+
...config2,
|
|
28
|
+
headers: {
|
|
29
|
+
...config2.headers,
|
|
30
|
+
[headerName]: token
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return config2;
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* 获取 CSRF Token
|
|
39
|
+
*/
|
|
40
|
+
getCSRFToken
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function createTokenRefreshInterceptor(config = {}) {
|
|
44
|
+
const {
|
|
45
|
+
statusCode = 401,
|
|
46
|
+
refreshToken,
|
|
47
|
+
isRefreshing = () => false,
|
|
48
|
+
pendingRequests = [],
|
|
49
|
+
updateHeaders,
|
|
50
|
+
retryTimes = 3
|
|
51
|
+
} = config;
|
|
52
|
+
const originalConfigs = /* @__PURE__ */ new Map();
|
|
53
|
+
let currentRetryTimes = retryTimes;
|
|
54
|
+
return {
|
|
55
|
+
/**
|
|
56
|
+
* 请求拦截
|
|
57
|
+
*/
|
|
58
|
+
onRequest: (config2) => {
|
|
59
|
+
originalConfigs.set(config2.requestId, config2);
|
|
60
|
+
return config2;
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* 响应拦截 - 处理 401
|
|
64
|
+
*/
|
|
65
|
+
onResponseError: async (error, _request) => {
|
|
66
|
+
const { response, config: errorConfig } = error;
|
|
67
|
+
if (response?.status !== statusCode) {
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
if (currentRetryTimes <= 0) {
|
|
71
|
+
currentRetryTimes = retryTimes;
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
const config2 = errorConfig;
|
|
75
|
+
if (!config2) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
if (isRefreshing()) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
pendingRequests.push(() => {
|
|
81
|
+
_request(config2).then(resolve).catch(reject);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (refreshToken) {
|
|
86
|
+
const refreshed = await refreshToken();
|
|
87
|
+
if (refreshed) {
|
|
88
|
+
if (updateHeaders && config2.headers) {
|
|
89
|
+
const newHeaders = { ...config2.headers };
|
|
90
|
+
updateHeaders(newHeaders);
|
|
91
|
+
config2.headers = newHeaders;
|
|
92
|
+
}
|
|
93
|
+
currentRetryTimes--;
|
|
94
|
+
return _request(config2);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* 重置重试次数
|
|
101
|
+
*/
|
|
102
|
+
resetRetryTimes: () => {
|
|
103
|
+
currentRetryTimes = retryTimes;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export function createSecurityInterceptor(options = {}) {
|
|
108
|
+
const { csrf = {}, tokenRefresh = {} } = options;
|
|
109
|
+
const csrfInterceptor = csrf === false ? null : createCSRFInterceptor(csrf);
|
|
110
|
+
const tokenRefreshInterceptor = tokenRefresh === false ? null : createTokenRefreshInterceptor(tokenRefresh);
|
|
111
|
+
return {
|
|
112
|
+
/**
|
|
113
|
+
* 请求拦截
|
|
114
|
+
*/
|
|
115
|
+
onRequest: (config) => {
|
|
116
|
+
let result = config;
|
|
117
|
+
if (csrfInterceptor) {
|
|
118
|
+
result = csrfInterceptor.onRequest(result);
|
|
119
|
+
}
|
|
120
|
+
if (tokenRefreshInterceptor) {
|
|
121
|
+
result = tokenRefreshInterceptor.onRequest(result);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* 获取 CSRF Token
|
|
127
|
+
*/
|
|
128
|
+
getCSRFToken: csrfInterceptor?.getCSRFToken,
|
|
129
|
+
/**
|
|
130
|
+
* 重置 Token 刷新状态
|
|
131
|
+
*/
|
|
132
|
+
resetTokenRefresh: tokenRefreshInterceptor?.resetRetryTimes
|
|
133
|
+
};
|
|
134
|
+
}
|
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.retryPlugin = exports.loggingPlugin = exports.errorHandlerPlugin = exports.cachePlugin = exports.builtInPlugins = exports.PluginManager = void 0;
|
|
7
|
+
class PluginManager {
|
|
8
|
+
plugins = /* @__PURE__ */new Map();
|
|
9
|
+
request = null;
|
|
10
|
+
lifecycleHooks = {};
|
|
11
|
+
/**
|
|
12
|
+
* 初始化插件管理器
|
|
13
|
+
*/
|
|
14
|
+
init(request) {
|
|
15
|
+
this.request = request;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 注册插件
|
|
19
|
+
*/
|
|
20
|
+
use(plugin, options) {
|
|
21
|
+
if (this.plugins.has(plugin.name)) {
|
|
22
|
+
console.warn(`Plugin ${plugin.name} is already installed`);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
if (!this.request) {
|
|
26
|
+
throw new Error("PluginManager must be initialized with a Request instance");
|
|
27
|
+
}
|
|
28
|
+
plugin.install(this.request, options);
|
|
29
|
+
this.plugins.set(plugin.name, {
|
|
30
|
+
plugin,
|
|
31
|
+
options,
|
|
32
|
+
installedAt: Date.now()
|
|
33
|
+
});
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 卸载插件
|
|
38
|
+
*/
|
|
39
|
+
uninstall(name) {
|
|
40
|
+
const instance = this.plugins.get(name);
|
|
41
|
+
if (!instance) return false;
|
|
42
|
+
if (instance.plugin.uninstall && this.request) {
|
|
43
|
+
instance.plugin.uninstall(this.request);
|
|
44
|
+
}
|
|
45
|
+
this.plugins.delete(name);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 获取插件
|
|
50
|
+
*/
|
|
51
|
+
get(name) {
|
|
52
|
+
return this.plugins.get(name);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 获取所有插件
|
|
56
|
+
*/
|
|
57
|
+
getAll() {
|
|
58
|
+
return Array.from(this.plugins.values());
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 检查插件是否已安装
|
|
62
|
+
*/
|
|
63
|
+
has(name) {
|
|
64
|
+
return this.plugins.has(name);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 清除所有插件
|
|
68
|
+
*/
|
|
69
|
+
clear() {
|
|
70
|
+
this.plugins.forEach((instance, name) => {
|
|
71
|
+
this.uninstall(name);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 注册生命周期钩子
|
|
76
|
+
*/
|
|
77
|
+
registerHooks(hooks) {
|
|
78
|
+
this.lifecycleHooks = {
|
|
79
|
+
...this.lifecycleHooks,
|
|
80
|
+
...hooks
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 获取生命周期钩子
|
|
85
|
+
*/
|
|
86
|
+
getHooks() {
|
|
87
|
+
return {
|
|
88
|
+
...this.lifecycleHooks
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.PluginManager = PluginManager;
|
|
93
|
+
const loggingPlugin = exports.loggingPlugin = {
|
|
94
|
+
name: "logging",
|
|
95
|
+
version: "1.0.0",
|
|
96
|
+
install(request) {
|
|
97
|
+
request.interceptors.request.use(config => {
|
|
98
|
+
console.log(`[YH-Request] \u2192 ${config.method} ${config.url}`);
|
|
99
|
+
return config;
|
|
100
|
+
});
|
|
101
|
+
request.interceptors.response.use(response => {
|
|
102
|
+
console.log(`[YH-Request] \u2190 ${response.response.status} ${response.config.url}`);
|
|
103
|
+
return response;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const cachePlugin = exports.cachePlugin = {
|
|
108
|
+
name: "cache",
|
|
109
|
+
version: "1.0.0",
|
|
110
|
+
install(request, options) {
|
|
111
|
+
request.interceptors.request.use(config => {
|
|
112
|
+
if (config.method === "GET" && options?.getCache) {
|
|
113
|
+
const key = config.url || "";
|
|
114
|
+
const cached = options.getCache(key);
|
|
115
|
+
if (cached) {
|
|
116
|
+
console.log("[YH-Request Cache] Cache hit:", key);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return config;
|
|
120
|
+
});
|
|
121
|
+
request.interceptors.response.use(response => {
|
|
122
|
+
if (response.config.method === "GET" && options?.setCache) {
|
|
123
|
+
const key = response.config.url || "";
|
|
124
|
+
options.setCache(key, response.data);
|
|
125
|
+
}
|
|
126
|
+
return response;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const errorHandlerPlugin = exports.errorHandlerPlugin = {
|
|
131
|
+
name: "errorHandler",
|
|
132
|
+
version: "1.0.0",
|
|
133
|
+
install(request, options) {
|
|
134
|
+
request.interceptors.response.use(response => response, error => {
|
|
135
|
+
if (options?.onError) {
|
|
136
|
+
options.onError(error);
|
|
137
|
+
}
|
|
138
|
+
return Promise.reject(error);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const retryPlugin = exports.retryPlugin = {
|
|
143
|
+
name: "retry",
|
|
144
|
+
version: "1.0.0",
|
|
145
|
+
install(request, options) {
|
|
146
|
+
const retries = options?.retries || 3;
|
|
147
|
+
const retryDelay = options?.retryDelay || 1e3;
|
|
148
|
+
request.interceptors.response.use(response => response, async error => {
|
|
149
|
+
const config = error.config;
|
|
150
|
+
if (!config) return Promise.reject(error);
|
|
151
|
+
const currentRetries = config._retryCount || 0;
|
|
152
|
+
if (currentRetries < retries) {
|
|
153
|
+
config._retryCount = currentRetries + 1;
|
|
154
|
+
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
|
155
|
+
return request.request(config);
|
|
156
|
+
}
|
|
157
|
+
return Promise.reject(error);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const builtInPlugins = exports.builtInPlugins = {
|
|
162
|
+
logging: loggingPlugin,
|
|
163
|
+
cache: cachePlugin,
|
|
164
|
+
errorHandler: errorHandlerPlugin,
|
|
165
|
+
retry: retryPlugin
|
|
166
|
+
};
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件系统
|
|
3
|
+
* 支持按需加载和树摇
|
|
4
|
+
*/
|
|
5
|
+
import { Request } from './request';
|
|
6
|
+
import type { InternalRequestOptions, RequestResponse } from './types';
|
|
7
|
+
/** 插件接口 */
|
|
8
|
+
export interface RequestPlugin {
|
|
9
|
+
/** 插件名称 */
|
|
10
|
+
name: string;
|
|
11
|
+
/** 插件版本 */
|
|
12
|
+
version?: string;
|
|
13
|
+
/** 安装插件 */
|
|
14
|
+
install: (request: Request, options?: Record<string, unknown>) => void;
|
|
15
|
+
/** 卸载插件 */
|
|
16
|
+
uninstall?: (request: Request) => void;
|
|
17
|
+
}
|
|
18
|
+
/** 插件实例 */
|
|
19
|
+
export interface PluginInstance {
|
|
20
|
+
/** 插件 */
|
|
21
|
+
plugin: RequestPlugin;
|
|
22
|
+
/** 选项 */
|
|
23
|
+
options?: Record<string, unknown>;
|
|
24
|
+
/** 安装时间 */
|
|
25
|
+
installedAt: number;
|
|
26
|
+
}
|
|
27
|
+
/** 请求生命周期钩子 */
|
|
28
|
+
export interface RequestLifecycleHooks {
|
|
29
|
+
/** 请求发送前 */
|
|
30
|
+
onRequest?: (config: InternalRequestOptions) => InternalRequestOptions | Promise<InternalRequestOptions>;
|
|
31
|
+
/** 请求发送后(成功) */
|
|
32
|
+
onResponse?: <T>(response: RequestResponse<T>) => RequestResponse<T> | Promise<RequestResponse<T>>;
|
|
33
|
+
/** 请求发送后(错误) */
|
|
34
|
+
onError?: (error: Error) => Error | Promise<Error>;
|
|
35
|
+
/** 请求完成(无论成功或失败) */
|
|
36
|
+
onFinally?: () => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 插件管理器
|
|
40
|
+
*/
|
|
41
|
+
export declare class PluginManager {
|
|
42
|
+
private plugins;
|
|
43
|
+
private request;
|
|
44
|
+
private lifecycleHooks;
|
|
45
|
+
/**
|
|
46
|
+
* 初始化插件管理器
|
|
47
|
+
*/
|
|
48
|
+
init(request: Request): void;
|
|
49
|
+
/**
|
|
50
|
+
* 注册插件
|
|
51
|
+
*/
|
|
52
|
+
use(plugin: RequestPlugin, options?: Record<string, unknown>): this;
|
|
53
|
+
/**
|
|
54
|
+
* 卸载插件
|
|
55
|
+
*/
|
|
56
|
+
uninstall(name: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* 获取插件
|
|
59
|
+
*/
|
|
60
|
+
get(name: string): PluginInstance | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* 获取所有插件
|
|
63
|
+
*/
|
|
64
|
+
getAll(): PluginInstance[];
|
|
65
|
+
/**
|
|
66
|
+
* 检查插件是否已安装
|
|
67
|
+
*/
|
|
68
|
+
has(name: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* 清除所有插件
|
|
71
|
+
*/
|
|
72
|
+
clear(): void;
|
|
73
|
+
/**
|
|
74
|
+
* 注册生命周期钩子
|
|
75
|
+
*/
|
|
76
|
+
registerHooks(hooks: RequestLifecycleHooks): void;
|
|
77
|
+
/**
|
|
78
|
+
* 获取生命周期钩子
|
|
79
|
+
*/
|
|
80
|
+
getHooks(): RequestLifecycleHooks;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 日志插件
|
|
84
|
+
*/
|
|
85
|
+
export declare const loggingPlugin: RequestPlugin;
|
|
86
|
+
/**
|
|
87
|
+
* 缓存插件
|
|
88
|
+
*/
|
|
89
|
+
export declare const cachePlugin: RequestPlugin;
|
|
90
|
+
/**
|
|
91
|
+
* 错误处理插件
|
|
92
|
+
*/
|
|
93
|
+
export declare const errorHandlerPlugin: RequestPlugin;
|
|
94
|
+
/**
|
|
95
|
+
* 重试插件
|
|
96
|
+
*/
|
|
97
|
+
export declare const retryPlugin: RequestPlugin;
|
|
98
|
+
/**
|
|
99
|
+
* 预定义插件集合
|
|
100
|
+
*/
|
|
101
|
+
export declare const builtInPlugins: {
|
|
102
|
+
logging: RequestPlugin;
|
|
103
|
+
cache: RequestPlugin;
|
|
104
|
+
errorHandler: RequestPlugin;
|
|
105
|
+
retry: RequestPlugin;
|
|
106
|
+
};
|