@dscli/request 0.1.0-alpha.0
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 +52 -0
- package/dist/axios/index.d.ts +34 -0
- package/dist/axios/index.d.ts.map +1 -0
- package/dist/axios/index.js +113 -0
- package/dist/axios/index.js.map +1 -0
- package/dist/core/errors.d.ts +20 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +19 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +167 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/types.d.ts +43 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/url.d.ts +8 -0
- package/dist/core/url.d.ts.map +1 -0
- package/dist/core/url.js +45 -0
- package/dist/core/url.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/vue/index.d.ts +9 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +21 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xionchan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @dscli/request
|
|
2
|
+
|
|
3
|
+
类型安全、可扩展且兼容 SSR 的请求客户端。根入口使用标准 Fetch API;axios 与 Vue 3 通过显式子路径按需导入。
|
|
4
|
+
|
|
5
|
+
> 当前为 `0.1.0-alpha.0` 本地候选,尚未发布到 npm。不要把它视为公共稳定版本。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
该候选尚未发布到 npm。在本仓库的联调项目中使用 workspace 协议:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pnpm --filter <consumer-package> add @dscli/request@workspace:*
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
公共 alpha 发布完成后,安装方式会更新为显式 `@alpha` 或精确版本。
|
|
16
|
+
|
|
17
|
+
## 用法
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createRequest, RequestError } from '@dscli/request'
|
|
21
|
+
|
|
22
|
+
const request = createRequest({
|
|
23
|
+
baseUrl: runtimeConfig.apiBaseUrl,
|
|
24
|
+
timeout: 8_000
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const data = await request.get<Data>('/data')
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof RequestError && error.kind === 'http') {
|
|
31
|
+
// 调用方处理 HTTP 状态和业务提示。
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 入口
|
|
37
|
+
|
|
38
|
+
- `@dscli/request`:`createRequest`、兼容包装 `dsRequest`、类型与 `RequestError`。
|
|
39
|
+
- `@dscli/request/axios`:`createAxiosRequest`,调用方传入 axios 兼容实例。
|
|
40
|
+
- `@dscli/request/vue`:`createRequestPlugin`、`requestClientKey`、`useRequest`。
|
|
41
|
+
|
|
42
|
+
axios 和 Vue 都是 optional peer dependency:仅在导入相应子路径时安装并使用它们。根入口不包含业务地址、token、自动重试或全局单例。
|
|
43
|
+
|
|
44
|
+
## 开发
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
pnpm --filter @dscli/request lint
|
|
48
|
+
pnpm --filter @dscli/request typecheck
|
|
49
|
+
pnpm --filter @dscli/request test
|
|
50
|
+
pnpm --filter @dscli/request build
|
|
51
|
+
pnpm verify:request
|
|
52
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { RequestClient, RequestOptions } from '../core/types.js';
|
|
2
|
+
/** axios 实例所需的最小结构,避免将 axios 打入本包。 */
|
|
3
|
+
export interface AxiosLike {
|
|
4
|
+
request<T = unknown>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
5
|
+
}
|
|
6
|
+
/** axios 使用小写的 arraybuffer/formdata,而统一契约保持 Fetch 风格命名。 */
|
|
7
|
+
export type AxiosResponseType = 'arraybuffer' | 'blob' | 'formdata' | 'json' | 'text';
|
|
8
|
+
export interface AxiosRequestConfig {
|
|
9
|
+
url: string;
|
|
10
|
+
method?: string;
|
|
11
|
+
baseURL?: string;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
params?: RequestOptions['query'];
|
|
14
|
+
data?: unknown;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
responseType?: AxiosResponseType;
|
|
18
|
+
}
|
|
19
|
+
export interface AxiosResponse<T> {
|
|
20
|
+
data: T;
|
|
21
|
+
status: number;
|
|
22
|
+
statusText?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface AxiosRequestClientOptions {
|
|
25
|
+
baseUrl?: string;
|
|
26
|
+
headers?: HeadersInit;
|
|
27
|
+
timeout?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 将调用方持有的 axios 实例适配为 RequestClient。
|
|
31
|
+
* axios 的拦截器、重试与认证仍由调用方在原实例上配置。
|
|
32
|
+
*/
|
|
33
|
+
export declare function createAxiosRequest(axios: AxiosLike, defaults?: AxiosRequestClientOptions): RequestClient;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/axios/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAuB,MAAM,kBAAkB,CAAA;AAE1F,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;CAC5E;AAED,2DAA2D;AAC3D,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;AAErF,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,MAAM,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAA;IACP,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAsDD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,QAAQ,GAAE,yBAA8B,GACvC,aAAa,CAgEf"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { RequestError } from '../core/errors.js';
|
|
2
|
+
function mergeHeaders(defaultHeaders, headers) {
|
|
3
|
+
const merged = new Headers(defaultHeaders);
|
|
4
|
+
if (headers)
|
|
5
|
+
for (const [key, value] of new Headers(headers))
|
|
6
|
+
merged.set(key, value);
|
|
7
|
+
return Object.fromEntries(merged.entries());
|
|
8
|
+
}
|
|
9
|
+
function normalizeTimeout(timeout) {
|
|
10
|
+
if (timeout === undefined || timeout === 0)
|
|
11
|
+
return undefined;
|
|
12
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
13
|
+
throw new RequestError('configuration', 'timeout 必须是非负有限毫秒数');
|
|
14
|
+
}
|
|
15
|
+
return timeout;
|
|
16
|
+
}
|
|
17
|
+
function createData(options, headers) {
|
|
18
|
+
if (options.body !== undefined && options.json !== undefined) {
|
|
19
|
+
throw new RequestError('configuration', 'body 与 json 不能同时提供');
|
|
20
|
+
}
|
|
21
|
+
if (options.body !== undefined)
|
|
22
|
+
return options.body;
|
|
23
|
+
if (options.json === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
if (!Object.keys(headers).some((key) => key.toLowerCase() === 'content-type')) {
|
|
26
|
+
headers['content-type'] = 'application/json';
|
|
27
|
+
}
|
|
28
|
+
return options.json;
|
|
29
|
+
}
|
|
30
|
+
/** 将统一响应类型转换为 axios 的运行时枚举,并在调用前拒绝无法表达的原始 Response。 */
|
|
31
|
+
function toAxiosResponseType(responseType) {
|
|
32
|
+
switch (responseType) {
|
|
33
|
+
case undefined:
|
|
34
|
+
return undefined;
|
|
35
|
+
case 'arrayBuffer':
|
|
36
|
+
return 'arraybuffer';
|
|
37
|
+
case 'formData':
|
|
38
|
+
return 'formdata';
|
|
39
|
+
case 'response':
|
|
40
|
+
throw new RequestError('configuration', 'axios 适配器不支持 response 响应类型');
|
|
41
|
+
default:
|
|
42
|
+
return responseType;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function createMethodRequest(request, method) {
|
|
46
|
+
return (url, json, options = {}) => request(url, { ...options, method, json });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 将调用方持有的 axios 实例适配为 RequestClient。
|
|
50
|
+
* axios 的拦截器、重试与认证仍由调用方在原实例上配置。
|
|
51
|
+
*/
|
|
52
|
+
export function createAxiosRequest(axios, defaults = {}) {
|
|
53
|
+
const defaultTimeout = normalizeTimeout(defaults.timeout);
|
|
54
|
+
const request = async (url, options = {}) => {
|
|
55
|
+
if (url.trim().length === 0)
|
|
56
|
+
throw new RequestError('configuration', '请求 URL 不能为空');
|
|
57
|
+
if (options.signal?.aborted) {
|
|
58
|
+
throw new RequestError('abort', '请求已被调用方取消', { url, cause: options.signal.reason });
|
|
59
|
+
}
|
|
60
|
+
const timeout = normalizeTimeout(options.timeout ?? defaultTimeout);
|
|
61
|
+
const headers = mergeHeaders(defaults.headers, options.headers);
|
|
62
|
+
const config = {
|
|
63
|
+
url,
|
|
64
|
+
method: (options.method ?? 'GET').toUpperCase(),
|
|
65
|
+
baseURL: defaults.baseUrl,
|
|
66
|
+
headers,
|
|
67
|
+
params: options.query,
|
|
68
|
+
data: createData(options, headers),
|
|
69
|
+
signal: options.signal,
|
|
70
|
+
timeout,
|
|
71
|
+
responseType: toAxiosResponseType(options.responseType)
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
const response = await axios.request(config);
|
|
75
|
+
if (response.status < 200 || response.status >= 300) {
|
|
76
|
+
throw new RequestError('http', `请求失败:${response.status}`, {
|
|
77
|
+
url,
|
|
78
|
+
status: response.status,
|
|
79
|
+
statusText: response.statusText
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return response.data;
|
|
83
|
+
}
|
|
84
|
+
catch (cause) {
|
|
85
|
+
if (cause instanceof RequestError)
|
|
86
|
+
throw cause;
|
|
87
|
+
const axiosError = cause;
|
|
88
|
+
if (axiosError.response?.status !== undefined) {
|
|
89
|
+
throw new RequestError('http', `请求失败:${axiosError.response.status}`, {
|
|
90
|
+
url,
|
|
91
|
+
status: axiosError.response.status,
|
|
92
|
+
statusText: axiosError.response.statusText,
|
|
93
|
+
cause
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (axiosError.code === 'ECONNABORTED') {
|
|
97
|
+
throw new RequestError('timeout', `请求超时:${timeout ?? 0}ms`, { url, cause });
|
|
98
|
+
}
|
|
99
|
+
if (options.signal?.aborted)
|
|
100
|
+
throw new RequestError('abort', '请求已被取消', { url, cause });
|
|
101
|
+
throw new RequestError('network', '请求网络失败', { url, cause });
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
request,
|
|
106
|
+
get: (url, options = {}) => request(url, { ...options, method: 'GET' }),
|
|
107
|
+
delete: (url, options = {}) => request(url, { ...options, method: 'DELETE' }),
|
|
108
|
+
post: createMethodRequest(request, 'POST'),
|
|
109
|
+
put: createMethodRequest(request, 'PUT'),
|
|
110
|
+
patch: createMethodRequest(request, 'PATCH')
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/axios/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** 可供调用方按失败类型处理的请求错误分类。 */
|
|
2
|
+
export type RequestErrorKind = 'configuration' | 'http' | 'network' | 'timeout' | 'abort' | 'parse';
|
|
3
|
+
export interface RequestErrorOptions {
|
|
4
|
+
url?: string;
|
|
5
|
+
status?: number;
|
|
6
|
+
statusText?: string;
|
|
7
|
+
cause?: unknown;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 为网络、HTTP、取消和解析失败提供统一上下文。
|
|
11
|
+
* cause 保留原始异常,避免调用方丢失运行时特有信息。
|
|
12
|
+
*/
|
|
13
|
+
export declare class RequestError extends Error {
|
|
14
|
+
readonly kind: RequestErrorKind;
|
|
15
|
+
readonly url?: string;
|
|
16
|
+
readonly status?: number;
|
|
17
|
+
readonly statusText?: string;
|
|
18
|
+
constructor(kind: RequestErrorKind, message: string, options?: RequestErrorOptions);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;AAEnG,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;gBAEhB,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB;CAQvF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 为网络、HTTP、取消和解析失败提供统一上下文。
|
|
3
|
+
* cause 保留原始异常,避免调用方丢失运行时特有信息。
|
|
4
|
+
*/
|
|
5
|
+
export class RequestError extends Error {
|
|
6
|
+
kind;
|
|
7
|
+
url;
|
|
8
|
+
status;
|
|
9
|
+
statusText;
|
|
10
|
+
constructor(kind, message, options = {}) {
|
|
11
|
+
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
12
|
+
this.name = 'RequestError';
|
|
13
|
+
this.kind = kind;
|
|
14
|
+
this.url = options.url;
|
|
15
|
+
this.status = options.status;
|
|
16
|
+
this.statusText = options.statusText;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAkB;IACtB,GAAG,CAAS;IACZ,MAAM,CAAS;IACf,UAAU,CAAS;IAE5B,YAAY,IAAsB,EAAE,OAAe,EAAE,UAA+B,EAAE;QACpF,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;QAClF,IAAI,CAAC,IAAI,GAAG,cAAc,CAAA;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;QACtB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAA;IACtC,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DsRequestOptions, RequestClient, RequestClientOptions } from './types.js';
|
|
2
|
+
export { RequestError } from './errors.js';
|
|
3
|
+
export type { RequestErrorKind, RequestErrorOptions } from './errors.js';
|
|
4
|
+
export type { DsRequestOptions, FetchImplementation, RequestClient, RequestClientOptions, RequestMethod, RequestOptions, RequestQuery, RequestQueryValue, RequestResponseType } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* 创建 fetch 请求客户端。函数在调用 request 前不会访问网络或浏览器全局。
|
|
7
|
+
*/
|
|
8
|
+
export declare function createRequest(defaults?: RequestClientOptions): RequestClient;
|
|
9
|
+
/** 保留旧 API;旧 body 一律按 JSON 序列化,新代码应优先使用 createRequest。 */
|
|
10
|
+
export declare function dsRequest<T = unknown>(url: string, options?: DsRequestOptions): Promise<T>;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAEhB,aAAa,EACb,oBAAoB,EAGrB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACxE,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AA0HnB;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,GAAE,oBAAyB,GAAG,aAAa,CA2DhF;AAID,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC,CAG9F"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { RequestError } from './errors.js';
|
|
2
|
+
import { appendQuery, normalizeTimeout, resolveRequestUrl } from './url.js';
|
|
3
|
+
export { RequestError } from './errors.js';
|
|
4
|
+
function createAbortContext(signal, timeout) {
|
|
5
|
+
if (!signal && !timeout) {
|
|
6
|
+
return { signal: undefined, timedOut: () => false, cleanup: () => undefined };
|
|
7
|
+
}
|
|
8
|
+
const controller = new AbortController();
|
|
9
|
+
let timeoutTriggered = false;
|
|
10
|
+
const abortFromCaller = () => controller.abort(signal?.reason);
|
|
11
|
+
if (signal?.aborted)
|
|
12
|
+
abortFromCaller();
|
|
13
|
+
else
|
|
14
|
+
signal?.addEventListener('abort', abortFromCaller, { once: true });
|
|
15
|
+
const timer = timeout
|
|
16
|
+
? setTimeout(() => {
|
|
17
|
+
timeoutTriggered = true;
|
|
18
|
+
controller.abort(new Error('请求超时'));
|
|
19
|
+
}, timeout)
|
|
20
|
+
: undefined;
|
|
21
|
+
return {
|
|
22
|
+
signal: controller.signal,
|
|
23
|
+
timedOut: () => timeoutTriggered,
|
|
24
|
+
cleanup: () => {
|
|
25
|
+
if (timer)
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
signal?.removeEventListener('abort', abortFromCaller);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function getFetchImplementation(injected) {
|
|
32
|
+
if (injected)
|
|
33
|
+
return injected;
|
|
34
|
+
if (typeof globalThis.fetch !== 'function') {
|
|
35
|
+
throw new RequestError('configuration', '当前运行时没有可用的 fetch,请通过 createRequest 注入 fetch');
|
|
36
|
+
}
|
|
37
|
+
return globalThis.fetch.bind(globalThis);
|
|
38
|
+
}
|
|
39
|
+
function mergeHeaders(defaultHeaders, headers) {
|
|
40
|
+
const merged = new Headers(defaultHeaders);
|
|
41
|
+
if (!headers)
|
|
42
|
+
return merged;
|
|
43
|
+
for (const [key, value] of new Headers(headers))
|
|
44
|
+
merged.set(key, value);
|
|
45
|
+
return merged;
|
|
46
|
+
}
|
|
47
|
+
function createBody(options, headers) {
|
|
48
|
+
if (options.body !== undefined && options.json !== undefined) {
|
|
49
|
+
throw new RequestError('configuration', 'body 与 json 不能同时提供');
|
|
50
|
+
}
|
|
51
|
+
if (options.body !== undefined)
|
|
52
|
+
return options.body;
|
|
53
|
+
if (options.json === undefined)
|
|
54
|
+
return undefined;
|
|
55
|
+
let serialized;
|
|
56
|
+
try {
|
|
57
|
+
serialized = JSON.stringify(options.json);
|
|
58
|
+
}
|
|
59
|
+
catch (cause) {
|
|
60
|
+
throw new RequestError('configuration', 'json 无法序列化', { cause });
|
|
61
|
+
}
|
|
62
|
+
if (serialized === undefined) {
|
|
63
|
+
throw new RequestError('configuration', 'json 必须是可序列化的值');
|
|
64
|
+
}
|
|
65
|
+
if (!headers.has('content-type'))
|
|
66
|
+
headers.set('content-type', 'application/json');
|
|
67
|
+
return serialized;
|
|
68
|
+
}
|
|
69
|
+
async function parseResponse(response, responseType) {
|
|
70
|
+
if (responseType === 'response')
|
|
71
|
+
return response;
|
|
72
|
+
if (responseType === 'json' &&
|
|
73
|
+
(response.status === 204 ||
|
|
74
|
+
response.status === 205 ||
|
|
75
|
+
response.headers.get('content-length') === '0')) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
switch (responseType) {
|
|
80
|
+
case 'json': {
|
|
81
|
+
// 部分服务会以 chunked 响应返回 200 空 body,此时没有 content-length 可供提前判断。
|
|
82
|
+
const text = await response.text();
|
|
83
|
+
return (text.length === 0 ? undefined : JSON.parse(text));
|
|
84
|
+
}
|
|
85
|
+
case 'text':
|
|
86
|
+
return (await response.text());
|
|
87
|
+
case 'blob':
|
|
88
|
+
return (await response.blob());
|
|
89
|
+
case 'arrayBuffer':
|
|
90
|
+
return (await response.arrayBuffer());
|
|
91
|
+
case 'formData':
|
|
92
|
+
return (await response.formData());
|
|
93
|
+
default:
|
|
94
|
+
return response;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (cause) {
|
|
98
|
+
throw new RequestError('parse', '响应内容无法按指定类型读取', { cause });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function createMethodRequest(request, method) {
|
|
102
|
+
return (url, json, options = {}) => request(url, { ...options, method, json });
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 创建 fetch 请求客户端。函数在调用 request 前不会访问网络或浏览器全局。
|
|
106
|
+
*/
|
|
107
|
+
export function createRequest(defaults = {}) {
|
|
108
|
+
const defaultTimeout = normalizeTimeout(defaults.timeout);
|
|
109
|
+
const request = async (url, options = {}) => {
|
|
110
|
+
const timeout = normalizeTimeout(options.timeout ?? defaultTimeout);
|
|
111
|
+
const resolvedUrl = appendQuery(resolveRequestUrl(url, defaults.baseUrl), options.query);
|
|
112
|
+
if (options.signal?.aborted) {
|
|
113
|
+
throw new RequestError('abort', '请求已被调用方取消', {
|
|
114
|
+
url: resolvedUrl,
|
|
115
|
+
cause: options.signal.reason
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const headers = mergeHeaders(defaults.headers, options.headers);
|
|
119
|
+
const body = createBody(options, headers);
|
|
120
|
+
const abortContext = createAbortContext(options.signal, timeout);
|
|
121
|
+
try {
|
|
122
|
+
const response = await getFetchImplementation(defaults.fetch)(resolvedUrl, {
|
|
123
|
+
method: (options.method ?? 'GET').toUpperCase(),
|
|
124
|
+
headers,
|
|
125
|
+
body,
|
|
126
|
+
signal: abortContext.signal
|
|
127
|
+
});
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
throw new RequestError('http', `请求失败:${response.status} ${response.statusText}`.trim(), {
|
|
130
|
+
url: resolvedUrl,
|
|
131
|
+
status: response.status,
|
|
132
|
+
statusText: response.statusText
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return await parseResponse(response, options.responseType ?? 'json');
|
|
136
|
+
}
|
|
137
|
+
catch (cause) {
|
|
138
|
+
if (cause instanceof RequestError)
|
|
139
|
+
throw cause;
|
|
140
|
+
if (abortContext.timedOut()) {
|
|
141
|
+
throw new RequestError('timeout', `请求超时:${timeout}ms`, { url: resolvedUrl, cause });
|
|
142
|
+
}
|
|
143
|
+
if (options.signal?.aborted || abortContext.signal?.aborted) {
|
|
144
|
+
throw new RequestError('abort', '请求已被取消', { url: resolvedUrl, cause });
|
|
145
|
+
}
|
|
146
|
+
throw new RequestError('network', '请求网络失败', { url: resolvedUrl, cause });
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
abortContext.cleanup();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
return {
|
|
153
|
+
request,
|
|
154
|
+
get: (url, options = {}) => request(url, { ...options, method: 'GET' }),
|
|
155
|
+
delete: (url, options = {}) => request(url, { ...options, method: 'DELETE' }),
|
|
156
|
+
post: createMethodRequest(request, 'POST'),
|
|
157
|
+
put: createMethodRequest(request, 'PUT'),
|
|
158
|
+
patch: createMethodRequest(request, 'PATCH')
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const defaultRequestClient = createRequest();
|
|
162
|
+
/** 保留旧 API;旧 body 一律按 JSON 序列化,新代码应优先使用 createRequest。 */
|
|
163
|
+
export function dsRequest(url, options = {}) {
|
|
164
|
+
const { body, ...requestOptions } = options;
|
|
165
|
+
return defaultRequestClient.request(url, { ...requestOptions, json: body });
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAU3E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAoB1C,SAAS,kBAAkB,CACzB,MAA+B,EAC/B,OAA2B;IAE3B,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAA;IAC/E,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,IAAI,gBAAgB,GAAG,KAAK,CAAA;IAC5B,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9D,IAAI,MAAM,EAAE,OAAO;QAAE,eAAe,EAAE,CAAA;;QACjC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvE,MAAM,KAAK,GAAG,OAAO;QACnB,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;YACd,gBAAgB,GAAG,IAAI,CAAA;YACvB,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;QACrC,CAAC,EAAE,OAAO,CAAC;QACb,CAAC,CAAC,SAAS,CAAA;IAEb,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,QAAQ,EAAE,GAAG,EAAE,CAAC,gBAAgB;QAChC,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YAC9B,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;QACvD,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,QAAyC;IACvE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,IAAI,OAAO,UAAU,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QAC3C,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,6CAA6C,CAC9C,CAAA;IACH,CAAC;IACD,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;AAC1C,CAAC;AAED,SAAS,YAAY,CACnB,cAAuC,EACvC,OAAgC;IAEhC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC,CAAA;IAC1C,IAAI,CAAC,OAAO;QAAE,OAAO,MAAM,CAAA;IAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACvE,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,UAAU,CAAC,OAAuB,EAAE,OAAgB;IAC3D,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7D,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAA;IAC/D,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,IAAI,CAAA;IACnD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAEhD,IAAI,UAA8B,CAAA;IAClC,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAA;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;IACjF,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,KAAK,UAAU,aAAa,CAAI,QAAkB,EAAE,YAAiC;IACnF,IAAI,YAAY,KAAK,UAAU;QAAE,OAAO,QAAa,CAAA;IACrD,IACE,YAAY,KAAK,MAAM;QACvB,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG;YACtB,QAAQ,CAAC,MAAM,KAAK,GAAG;YACvB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,GAAG,CAAC,EACjD,CAAC;QACD,OAAO,SAAc,CAAA;IACvB,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,YAAY,EAAE,CAAC;YACrB,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,6DAA6D;gBAC7D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBAClC,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAM,CAAA;YAChE,CAAC;YACD,KAAK,MAAM;gBACT,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAA;YACrC,KAAK,MAAM;gBACT,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAA;YACrC,KAAK,aAAa;gBAChB,OAAO,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAM,CAAA;YAC5C,KAAK,UAAU;gBACb,OAAO,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAM,CAAA;YACzC;gBACE,OAAO,QAAa,CAAA;QACxB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAC7D,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAiC,EAAE,MAAgC;IAC9F,OAAO,CACL,GAAW,EACX,IAAc,EACd,UAA4D,EAAE,EAC9D,EAAE,CAAC,OAAO,CAAI,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,WAAiC,EAAE;IAC/D,MAAM,cAAc,GAAG,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAEzD,MAAM,OAAO,GAAG,KAAK,EAAe,GAAW,EAAE,UAA0B,EAAE,EAAc,EAAE;QAC3F,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,IAAI,cAAc,CAAC,CAAA;QACnE,MAAM,WAAW,GAAG,WAAW,CAAC,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;QACxF,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE;gBAC3C,GAAG,EAAE,WAAW;gBAChB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM;aAC7B,CAAC,CAAA;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;QAC/D,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACzC,MAAM,YAAY,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAChE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;gBACzE,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE;gBAC/C,OAAO;gBACP,IAAI;gBACJ,MAAM,EAAE,YAAY,CAAC,MAAM;aAC5B,CAAC,CAAA;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,YAAY,CACpB,MAAM,EACN,QAAQ,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EACvD;oBACE,GAAG,EAAE,WAAW;oBAChB,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;iBAChC,CACF,CAAA;YACH,CAAC;YACD,OAAO,MAAM,aAAa,CAAI,QAAQ,EAAE,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC,CAAA;QACzE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,YAAY;gBAAE,MAAM,KAAK,CAAA;YAC9C,IAAI,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC5B,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,QAAQ,OAAO,IAAI,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;YACrF,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;gBAC5D,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;YACxE,CAAC;YACD,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;QAC1E,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,OAAO,EAAE,CAAA;QACxB,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,OAAO;QACP,GAAG,EAAE,CAAc,GAAW,EAAE,UAA0C,EAAE,EAAE,EAAE,CAC9E,OAAO,CAAI,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAChD,MAAM,EAAE,CAAc,GAAW,EAAE,UAA0C,EAAE,EAAE,EAAE,CACjF,OAAO,CAAI,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACnD,IAAI,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC;QAC1C,GAAG,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC;QACxC,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;KAC7C,CAAA;AACH,CAAC;AAED,MAAM,oBAAoB,GAAG,aAAa,EAAE,CAAA;AAE5C,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CAAc,GAAW,EAAE,UAA4B,EAAE;IAChF,MAAM,EAAE,IAAI,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAA;IAC3C,OAAO,oBAAoB,CAAC,OAAO,CAAI,GAAG,EAAE,EAAE,GAAG,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;AAChF,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** 支持自定义方法名,同时为常用 HTTP 方法提供自动补全。 */
|
|
2
|
+
export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | (string & {});
|
|
3
|
+
/** 请求客户端能够读取的响应形式。 */
|
|
4
|
+
export type RequestResponseType = 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'response';
|
|
5
|
+
export type RequestQueryValue = string | number | boolean | bigint | null | undefined;
|
|
6
|
+
/** query 数组会在最终 URL 中编码为重复参数。 */
|
|
7
|
+
export type RequestQuery = Record<string, RequestQueryValue | readonly RequestQueryValue[]>;
|
|
8
|
+
/** 允许在测试、SSR 或受控运行时中注入 fetch 实现。 */
|
|
9
|
+
export type FetchImplementation = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
10
|
+
/** 单次请求选项。`body` 用于原始 BodyInit,`json` 用于 JSON 序列化,两者不能同时出现。 */
|
|
11
|
+
export interface RequestOptions {
|
|
12
|
+
method?: RequestMethod;
|
|
13
|
+
headers?: HeadersInit;
|
|
14
|
+
query?: RequestQuery;
|
|
15
|
+
body?: BodyInit | null;
|
|
16
|
+
json?: unknown;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
/** 毫秒;0 或 undefined 表示不设置超时。 */
|
|
19
|
+
timeout?: number;
|
|
20
|
+
responseType?: RequestResponseType;
|
|
21
|
+
}
|
|
22
|
+
/** 创建 fetch 请求客户端的默认选项。 */
|
|
23
|
+
export interface RequestClientOptions {
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
headers?: HeadersInit;
|
|
26
|
+
fetch?: FetchImplementation;
|
|
27
|
+
/** 毫秒;可被单次请求的 timeout 覆盖。 */
|
|
28
|
+
timeout?: number;
|
|
29
|
+
}
|
|
30
|
+
/** 统一的请求客户端契约,供 fetch、axios 和 Vue 注入共用。 */
|
|
31
|
+
export interface RequestClient {
|
|
32
|
+
request<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
|
|
33
|
+
get<T = unknown>(url: string, options?: Omit<RequestOptions, 'method'>): Promise<T>;
|
|
34
|
+
delete<T = unknown>(url: string, options?: Omit<RequestOptions, 'method'>): Promise<T>;
|
|
35
|
+
post<T = unknown>(url: string, json?: unknown, options?: Omit<RequestOptions, 'method' | 'json' | 'body'>): Promise<T>;
|
|
36
|
+
put<T = unknown>(url: string, json?: unknown, options?: Omit<RequestOptions, 'method' | 'json' | 'body'>): Promise<T>;
|
|
37
|
+
patch<T = unknown>(url: string, json?: unknown, options?: Omit<RequestOptions, 'method' | 'json' | 'body'>): Promise<T>;
|
|
38
|
+
}
|
|
39
|
+
/** 旧 dsRequest 的兼容选项;body 始终按 JSON 数据处理。 */
|
|
40
|
+
export interface DsRequestOptions extends Omit<RequestOptions, 'body' | 'json'> {
|
|
41
|
+
body?: unknown;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RequestQuery } from './types.js';
|
|
2
|
+
/** 校验请求超时,避免 setTimeout 接收 NaN、负数或无穷大。 */
|
|
3
|
+
export declare function normalizeTimeout(timeout: number | undefined): number | undefined;
|
|
4
|
+
/** 解析基础 URL;未提供基础 URL 时保留相对 URL 交由运行时 fetch 处理。 */
|
|
5
|
+
export declare function resolveRequestUrl(url: string, baseUrl: string | undefined): string;
|
|
6
|
+
/** 在保留现有 query 与 hash 的前提下追加 query;null 和 undefined 值会被忽略。 */
|
|
7
|
+
export declare function appendQuery(url: string, query: RequestQuery | undefined): string;
|
|
8
|
+
//# sourceMappingURL=url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/core/url.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMhF;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAWlF;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,CAqBhF"}
|
package/dist/core/url.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RequestError } from './errors.js';
|
|
2
|
+
/** 校验请求超时,避免 setTimeout 接收 NaN、负数或无穷大。 */
|
|
3
|
+
export function normalizeTimeout(timeout) {
|
|
4
|
+
if (timeout === undefined || timeout === 0)
|
|
5
|
+
return undefined;
|
|
6
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
7
|
+
throw new RequestError('configuration', 'timeout 必须是非负有限毫秒数');
|
|
8
|
+
}
|
|
9
|
+
return timeout;
|
|
10
|
+
}
|
|
11
|
+
/** 解析基础 URL;未提供基础 URL 时保留相对 URL 交由运行时 fetch 处理。 */
|
|
12
|
+
export function resolveRequestUrl(url, baseUrl) {
|
|
13
|
+
if (url.trim().length === 0) {
|
|
14
|
+
throw new RequestError('configuration', '请求 URL 不能为空');
|
|
15
|
+
}
|
|
16
|
+
if (!baseUrl)
|
|
17
|
+
return url;
|
|
18
|
+
try {
|
|
19
|
+
return new URL(url, baseUrl).toString();
|
|
20
|
+
}
|
|
21
|
+
catch (cause) {
|
|
22
|
+
throw new RequestError('configuration', '请求 URL 或 baseUrl 无效', { url, cause });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** 在保留现有 query 与 hash 的前提下追加 query;null 和 undefined 值会被忽略。 */
|
|
26
|
+
export function appendQuery(url, query) {
|
|
27
|
+
if (!query || Object.keys(query).length === 0)
|
|
28
|
+
return url;
|
|
29
|
+
const hashIndex = url.indexOf('#');
|
|
30
|
+
const fragment = hashIndex === -1 ? '' : url.slice(hashIndex);
|
|
31
|
+
const withoutFragment = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
32
|
+
const queryIndex = withoutFragment.indexOf('?');
|
|
33
|
+
const pathname = queryIndex === -1 ? withoutFragment : withoutFragment.slice(0, queryIndex);
|
|
34
|
+
const parameters = new URLSearchParams(queryIndex === -1 ? '' : withoutFragment.slice(queryIndex + 1));
|
|
35
|
+
for (const [key, value] of Object.entries(query)) {
|
|
36
|
+
const values = Array.isArray(value) ? value : [value];
|
|
37
|
+
for (const item of values) {
|
|
38
|
+
if (item !== null && item !== undefined)
|
|
39
|
+
parameters.append(key, String(item));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const serialized = parameters.toString();
|
|
43
|
+
return `${pathname}${serialized ? `?${serialized}` : ''}${fragment}`;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/core/url.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createRequest, dsRequest, RequestError } from './core/index.js';
|
|
2
|
+
export type { DsRequestOptions, FetchImplementation, RequestClient, RequestClientOptions, RequestErrorKind, RequestErrorOptions, RequestMethod, RequestOptions, RequestQuery, RequestQueryValue, RequestResponseType } from './core/index.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACxE,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InjectionKey, Plugin } from 'vue';
|
|
2
|
+
import type { RequestClient } from '../core/types.js';
|
|
3
|
+
/** Vue 组件中注入 RequestClient 的稳定 key。 */
|
|
4
|
+
export declare const requestClientKey: InjectionKey<RequestClient>;
|
|
5
|
+
/** 创建 Vue 3 plugin;同一个客户端可由多个应用分别安装。 */
|
|
6
|
+
export declare function createRequestPlugin(client: RequestClient): Plugin;
|
|
7
|
+
/** 在组件 setup 上下文中取得已通过 createRequestPlugin 安装的请求客户端。 */
|
|
8
|
+
export declare function useRequest(): RequestClient;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAO,YAAY,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAEpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,uCAAuC;AACvC,eAAO,MAAM,gBAAgB,EAAE,YAAY,CAAC,aAAa,CAAkC,CAAA;AAE3F,wCAAwC;AACxC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAMjE;AAED,wDAAwD;AACxD,wBAAgB,UAAU,IAAI,aAAa,CAM1C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { inject } from 'vue';
|
|
2
|
+
import { RequestError } from '../core/errors.js';
|
|
3
|
+
/** Vue 组件中注入 RequestClient 的稳定 key。 */
|
|
4
|
+
export const requestClientKey = Symbol('dscli-request-client');
|
|
5
|
+
/** 创建 Vue 3 plugin;同一个客户端可由多个应用分别安装。 */
|
|
6
|
+
export function createRequestPlugin(client) {
|
|
7
|
+
return {
|
|
8
|
+
install(app) {
|
|
9
|
+
app.provide(requestClientKey, client);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** 在组件 setup 上下文中取得已通过 createRequestPlugin 安装的请求客户端。 */
|
|
14
|
+
export function useRequest() {
|
|
15
|
+
const client = inject(requestClientKey, undefined);
|
|
16
|
+
if (!client) {
|
|
17
|
+
throw new RequestError('configuration', '未找到 RequestClient,请先安装 createRequestPlugin');
|
|
18
|
+
}
|
|
19
|
+
return client;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,uCAAuC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAgC,MAAM,CAAC,sBAAsB,CAAC,CAAA;AAE3F,wCAAwC;AACxC,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,OAAO;QACL,OAAO,CAAC,GAAQ;YACd,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAA;QACvC,CAAC;KACF,CAAA;AACH,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAA;IAClD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,4CAA4C,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dscli/request",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "类型安全、可扩展且兼容 SSR 的 fetch 请求客户端",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"clean": "node ./scripts/clean.mjs",
|
|
8
|
+
"build": "pnpm run clean && tsc -p tsconfig.build.json",
|
|
9
|
+
"lint": "eslint src scripts --max-warnings 0",
|
|
10
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
11
|
+
"test": "vitest run --root ../.. packages/request/src",
|
|
12
|
+
"verify:package": "node ./scripts/verify-package.mjs",
|
|
13
|
+
"prepack": "pnpm run build"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./axios": {
|
|
21
|
+
"types": "./dist/axios/index.d.ts",
|
|
22
|
+
"import": "./dist/axios/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./vue": {
|
|
25
|
+
"types": "./dist/vue/index.d.ts",
|
|
26
|
+
"import": "./dist/vue/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": "^22.18.0 || >=24.12.0"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"request",
|
|
40
|
+
"fetch",
|
|
41
|
+
"axios",
|
|
42
|
+
"vue",
|
|
43
|
+
"typescript",
|
|
44
|
+
"ssr"
|
|
45
|
+
],
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://gitee.com/xionchan/dscli.git",
|
|
49
|
+
"directory": "packages/request"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public",
|
|
53
|
+
"registry": "https://registry.npmjs.org/",
|
|
54
|
+
"tag": "alpha"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"axios": "^1.0.0",
|
|
58
|
+
"vue": "^3.5.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"axios": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"vue": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/node": "^24.0.0",
|
|
70
|
+
"typescript": "catalog:",
|
|
71
|
+
"vitest": "catalog:",
|
|
72
|
+
"vue": "catalog:"
|
|
73
|
+
},
|
|
74
|
+
"author": "游于艺(wx58012007)",
|
|
75
|
+
"license": "MIT"
|
|
76
|
+
}
|