@zwa73/utils 1.0.294 → 1.0.295
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/dist/UtilFunctions.d.ts +1 -1
- package/dist/UtilHttp.d.ts +59 -87
- package/dist/UtilHttp.js +189 -260
- package/dist/UtilInterfaces.d.ts +1 -1
- package/dist/UtilLogger.d.ts +16 -15
- package/dist/UtilLogger.js +32 -7
- package/package.json +2 -2
package/dist/UtilFunctions.d.ts
CHANGED
|
@@ -57,6 +57,6 @@ declare class _UtilFunc {
|
|
|
57
57
|
*/
|
|
58
58
|
static resolveDataStore<T>(source: ParseableDataStore<T>): DataStore<T>;
|
|
59
59
|
}
|
|
60
|
-
export declare const UtilFunc: import("@zwa73/modular-mixer").ComposedClass<typeof _UtilFunc, typeof JsFunc, "__jsUtils", "prototype" | "preset" | "assignOption" | "genUUID" | "getTime" | "initField" | "initObject" | "afterward" | "sleep" | "getNeverResolvedPromise" | "retryPromise" | "timelimitPromise" | "mapEntries" | "eachField" | "stringifyJToken" | "sortJToken" | "constrainType" | "constrainLiteral" | "assertType" | "deepClone" | "isSafeNumber" | "dedent" | "throwError" | "getStack" | "getFuncLoc" | "cachePool" | "memoize" | "asyncize" | "lazyFunction" | "iocify" | "splitToChunk" | "mergeFromChunk" | "structEqual" | "concurrent" | "dynamicImport" | "createInjectable" | "createAsyncProxy" | "checkSharpSchema" | "unwarpReadonly" | "outcome" | "extractOutcome" | "success" | "failed" | "match" | "isStatus" | "eitherize" | "parseSrtTime" | "formatSrtTime" | "parseSrt" | "createSrt" | "ivk" | "range" | "s2l" | "l2s">;
|
|
60
|
+
export declare const UtilFunc: import("@zwa73/modular-mixer").ComposedClass<typeof _UtilFunc, typeof JsFunc, "__jsUtils", "prototype" | "preset" | "assignOption" | "genUUID" | "getTime" | "initField" | "initObject" | "afterward" | "sleep" | "getNeverResolvedPromise" | "retryPromise" | "timelimitPromise" | "mapEntries" | "eachField" | "stringifyJToken" | "sortJToken" | "constrainType" | "constrainLiteral" | "assertType" | "deepClone" | "isSafeNumber" | "dedent" | "throwError" | "getStack" | "getFuncLoc" | "cachePool" | "memoize" | "asyncize" | "lazyFunction" | "iocify" | "splitToChunk" | "mergeFromChunk" | "structEqual" | "concurrent" | "dynamicImport" | "createInjectable" | "createAsyncProxy" | "checkSharpSchema" | "unwarpReadonly" | "wrapILogger" | "outcome" | "extractOutcome" | "success" | "failed" | "match" | "isStatus" | "eitherize" | "parseSrtTime" | "formatSrtTime" | "parseSrt" | "createSrt" | "ivk" | "range" | "s2l" | "l2s">;
|
|
61
61
|
export type UtilFunc = typeof UtilFunc;
|
|
62
62
|
export {};
|
package/dist/UtilHttp.d.ts
CHANGED
|
@@ -1,93 +1,82 @@
|
|
|
1
|
-
import http from 'http';
|
|
2
1
|
import type { LogLevel, PromiseRetries } from "@zwa73/js-utils";
|
|
3
2
|
import { PromiseQueue } from "@zwa73/js-utils";
|
|
4
|
-
import
|
|
3
|
+
import type { Dispatcher } from "undici";
|
|
5
4
|
import type { AnyString, JToken, MPromise, PartialOption, StatusVerifyFn } from "./UtilInterfaces";
|
|
6
|
-
|
|
5
|
+
/** 网络请求返回值 */
|
|
7
6
|
export type RequestResult<T> = {
|
|
8
|
-
|
|
9
|
-
headers:
|
|
10
|
-
|
|
7
|
+
/** 响应头 */
|
|
8
|
+
headers: Record<string, string | string[] | undefined>;
|
|
9
|
+
/** 响应状态码 */
|
|
11
10
|
statusCode?: number;
|
|
12
|
-
|
|
11
|
+
/** 响应数据 */
|
|
13
12
|
data: T;
|
|
14
13
|
};
|
|
15
14
|
/**网络请求选项 */
|
|
16
15
|
export type RequestOption = {
|
|
17
|
-
|
|
16
|
+
/** 请求的log等级 默认http 不影响警告 */
|
|
18
17
|
logLevel?: LogLevel;
|
|
19
|
-
|
|
18
|
+
/** 请求协议 */
|
|
20
19
|
protocol: 'http:' | 'https:';
|
|
21
|
-
|
|
20
|
+
/** 超时时间/毫秒 最小为10_000 默认无限 传入signal时无效 */
|
|
22
21
|
timeout?: number;
|
|
23
|
-
|
|
22
|
+
/** 请求域名 */
|
|
24
23
|
hostname: string;
|
|
25
|
-
|
|
24
|
+
/** 请求路径 */
|
|
26
25
|
path?: string;
|
|
27
|
-
|
|
28
|
-
method: 'POST' | 'GET';
|
|
29
|
-
|
|
26
|
+
/** 请求方式 */
|
|
27
|
+
method: 'POST' | 'GET' | AnyString;
|
|
28
|
+
/** 端口 */
|
|
30
29
|
port?: number;
|
|
31
30
|
/**请求头 */
|
|
32
|
-
headers?: {
|
|
31
|
+
headers?: Record<string, string> & {
|
|
33
32
|
/**内容类型 */
|
|
34
33
|
'Content-Type'?: 'application/json' | 'multipart/form-data' | AnyString;
|
|
35
34
|
/**内容长度 一般无需填写 应为buffer长度而非字符串长度 */
|
|
36
35
|
'Content-Length'?: number;
|
|
37
36
|
};
|
|
38
37
|
/**响应buffer的编码 默认utf8 */
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
/** 自定义网络调度器 (如 undici 的 ProxyAgent / MockAgent) */
|
|
39
|
+
dispatcher?: Dispatcher;
|
|
40
|
+
/** 外部传入的取消信号,如果传入,内部将不再自动根据 timeout 创建 AbortController */
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
};
|
|
41
43
|
/**getquery请求所允许的数据 */
|
|
42
44
|
export type QueryRequestData = NodeJS.Dict<string | number | boolean | readonly string[] | readonly number[] | readonly boolean[] | null>;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/**数据处理函数 */
|
|
48
|
-
export type RequestReduceFn<T> = (acc: T, data: string) => MPromise<T>;
|
|
49
|
-
/**数据初始化函数 */
|
|
50
|
-
export type RequestInitFn<T> = (res: http.IncomingMessage) => MPromise<T>;
|
|
51
|
-
/**accept处理数据
|
|
52
|
-
* @template D - 接受时转换的数据类型
|
|
53
|
-
* @template R - 完成处理的数据类型
|
|
45
|
+
/** accept处理配置 */
|
|
46
|
+
type AcceptProcCtor<R, T extends {}> = AcceptProcData<R> | ((arg: T) => MPromise<AcceptProcData<R>>);
|
|
47
|
+
/** 接受处理数据
|
|
48
|
+
* @template R - 最终向外返回的数据类型
|
|
54
49
|
*/
|
|
55
|
-
type
|
|
56
|
-
|
|
57
|
-
init: RequestInitFn<D>;
|
|
58
|
-
reduce?: RequestReduceFn<D>;
|
|
59
|
-
parse: RequestParseFn<D, R>;
|
|
50
|
+
type AcceptProcData<R> = {
|
|
51
|
+
parseResponse: (response: Response, opt: RequestOption) => MPromise<R>;
|
|
60
52
|
};
|
|
61
|
-
/**send
|
|
53
|
+
/** send处理配置 */
|
|
62
54
|
type SendProcCtor<T extends {}> = SendProcData | ((opt: RequestOption, arg: T) => MPromise<SendProcData>);
|
|
55
|
+
/** fetch发送处理数据配置 */
|
|
63
56
|
type SendProcData = {
|
|
64
|
-
|
|
57
|
+
body?: BodyInit;
|
|
58
|
+
headers?: Record<string, string>;
|
|
65
59
|
};
|
|
66
60
|
declare const SendNoneProc: SendProcCtor<{}>;
|
|
67
|
-
declare const AcceptStringProc: AcceptProcCtor<
|
|
68
|
-
declare const AcceptNoneProc: AcceptProcCtor<
|
|
69
|
-
/**send处理的参数 */
|
|
61
|
+
declare const AcceptStringProc: AcceptProcCtor<RequestResult<string> | undefined, {}>;
|
|
62
|
+
declare const AcceptNoneProc: AcceptProcCtor<RequestResult<undefined> | undefined, {}>;
|
|
70
63
|
type SendParams<S extends SendProcCtor<any>> = S extends SendProcCtor<infer P> ? P : never;
|
|
71
|
-
|
|
72
|
-
type AcceptParams<A extends AcceptProcCtor<any, any, any>> = A extends AcceptProcCtor<any, any, infer P> ? P : never;
|
|
64
|
+
type AcceptParams<A extends AcceptProcCtor<any, any>> = A extends AcceptProcCtor<any, infer P> ? P : never;
|
|
73
65
|
type HasConflict<A, B> = keyof A & keyof B extends never ? false : true;
|
|
74
66
|
type ConflictCheck<A, B, C> = HasConflict<A, B> extends true ? A & B & C & Error & "❌ A 与 B 有字段冲突" : HasConflict<A, C> extends true ? A & B & C & Error & "❌ A 与 C 有字段冲突" : HasConflict<B, C> extends true ? A & B & C & Error & "❌ B 与 C 有字段冲突" : A & B & C;
|
|
75
|
-
|
|
76
|
-
type ParseResult<P extends AcceptProcCtor<any, any, any>> = P extends AcceptProcCtor<any, infer T, any> ? Awaited<T> : never;
|
|
67
|
+
type ParseResult<P extends AcceptProcCtor<any, any>> = P extends AcceptProcCtor<infer T, any> ? Awaited<T> : never;
|
|
77
68
|
/**http请求工具 */
|
|
78
|
-
export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<RequestOption, 'protocol'>>, S extends SendProcCtor<any>, A extends AcceptProcCtor<any, any
|
|
69
|
+
export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<RequestOption, 'protocol'>>, S extends SendProcCtor<any>, A extends AcceptProcCtor<any, any>> {
|
|
79
70
|
private _data;
|
|
80
71
|
private _send;
|
|
81
72
|
private _accept;
|
|
82
73
|
private constructor();
|
|
83
|
-
/**设为https请求 */
|
|
84
74
|
static https(): UtilHttp<{
|
|
85
75
|
readonly protocol: "https:";
|
|
86
|
-
}, SendProcCtor<{}>, AcceptProcCtor<
|
|
87
|
-
/**设为http请求 */
|
|
76
|
+
}, SendProcCtor<{}>, AcceptProcCtor<RequestResult<string> | undefined, {}>>;
|
|
88
77
|
static http(): UtilHttp<{
|
|
89
78
|
readonly protocol: "http:";
|
|
90
|
-
}, SendProcCtor<{}>, AcceptProcCtor<
|
|
79
|
+
}, SendProcCtor<{}>, AcceptProcCtor<RequestResult<string> | undefined, {}>>;
|
|
91
80
|
/**从url创建 */
|
|
92
81
|
static url(urlStr: `${'http:' | 'https:'}//${string}`): UtilHttp<{
|
|
93
82
|
protocol: "http:" | "https:";
|
|
@@ -95,7 +84,7 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
95
84
|
hostname: string;
|
|
96
85
|
path: string;
|
|
97
86
|
port: number | undefined;
|
|
98
|
-
}, SendProcCtor<{}>, AcceptProcCtor<
|
|
87
|
+
}, SendProcCtor<{}>, AcceptProcCtor<RequestResult<string> | undefined, {}>>;
|
|
99
88
|
/**设为get方式的请求 */
|
|
100
89
|
get(): UtilHttp<D & {
|
|
101
90
|
method: "GET";
|
|
@@ -110,8 +99,8 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
110
99
|
*/
|
|
111
100
|
option<OPT extends Partial<RequestOption>>(option: OPT): UtilHttp<D & OPT, S, A>;
|
|
112
101
|
/**补充header */
|
|
113
|
-
header
|
|
114
|
-
headers:
|
|
102
|
+
header(headers: Record<string, string>): UtilHttp<D & {
|
|
103
|
+
headers: typeof headers;
|
|
115
104
|
}, S, A>;
|
|
116
105
|
/**添加一段query */
|
|
117
106
|
query(data: QueryRequestData): this;
|
|
@@ -123,9 +112,8 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
123
112
|
"Content-Type": "application/json";
|
|
124
113
|
};
|
|
125
114
|
}, (opt: RequestOption, arg: {
|
|
126
|
-
/**发送的json */
|
|
127
115
|
json: JToken;
|
|
128
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
116
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
129
117
|
/**收发皆为json的post预设 */
|
|
130
118
|
postJson(): UtilHttp<D & {
|
|
131
119
|
method: "POST";
|
|
@@ -134,20 +122,18 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
134
122
|
'Content-Type': "application/json";
|
|
135
123
|
};
|
|
136
124
|
}, (opt: RequestOption, arg: {
|
|
137
|
-
/**发送的json */
|
|
138
125
|
json: JToken;
|
|
139
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
126
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
140
127
|
/**无查询参数获取json的get预设 */
|
|
141
128
|
getJson(): UtilHttp<D & {
|
|
142
129
|
method: "GET";
|
|
143
|
-
}, SendProcCtor<{}>, AcceptProcData<
|
|
130
|
+
}, SendProcCtor<{}>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
144
131
|
/**有查询参数获取json的get预设 */
|
|
145
132
|
queryJson(): UtilHttp<D & {
|
|
146
133
|
method: "GET";
|
|
147
134
|
}, (opt: RequestOption, arg: {
|
|
148
|
-
/**附加的查询表单数据 */
|
|
149
135
|
query: QueryRequestData;
|
|
150
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
136
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
151
137
|
/**收发皆为json的https-post预设 */
|
|
152
138
|
static httpsPostJson(): UtilHttp<{
|
|
153
139
|
readonly protocol: "https:";
|
|
@@ -158,9 +144,8 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
158
144
|
'Content-Type': "application/json";
|
|
159
145
|
};
|
|
160
146
|
}, (opt: RequestOption, arg: {
|
|
161
|
-
/**发送的json */
|
|
162
147
|
json: JToken;
|
|
163
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
148
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
164
149
|
/**收发皆为json的http-post预设 */
|
|
165
150
|
static httpPostJson(): UtilHttp<{
|
|
166
151
|
readonly protocol: "http:";
|
|
@@ -171,56 +156,49 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
171
156
|
'Content-Type': "application/json";
|
|
172
157
|
};
|
|
173
158
|
}, (opt: RequestOption, arg: {
|
|
174
|
-
/**发送的json */
|
|
175
159
|
json: JToken;
|
|
176
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
160
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
177
161
|
/**无查询参数获取json的https-get预设 */
|
|
178
162
|
static httpsGetJson(): UtilHttp<{
|
|
179
163
|
readonly protocol: "https:";
|
|
180
164
|
} & {
|
|
181
165
|
method: "GET";
|
|
182
|
-
}, SendProcCtor<{}>, AcceptProcData<
|
|
166
|
+
}, SendProcCtor<{}>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
183
167
|
/**有查询参数获取json的https-get预设 */
|
|
184
168
|
static httpsQueryJson(): UtilHttp<{
|
|
185
169
|
readonly protocol: "http:";
|
|
186
170
|
} & {
|
|
187
171
|
method: "GET";
|
|
188
172
|
}, (opt: RequestOption, arg: {
|
|
189
|
-
/**附加的查询表单数据 */
|
|
190
173
|
query: QueryRequestData;
|
|
191
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
174
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
192
175
|
/**无查询参数获取json的http-get预设 */
|
|
193
176
|
static httpGetJson(): UtilHttp<{
|
|
194
177
|
readonly protocol: "http:";
|
|
195
178
|
} & {
|
|
196
179
|
method: "GET";
|
|
197
|
-
}, SendProcCtor<{}>, AcceptProcData<
|
|
180
|
+
}, SendProcCtor<{}>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
198
181
|
/**有查询参数获取json的http-get预设 */
|
|
199
182
|
static httpQueryJson(): UtilHttp<{
|
|
200
183
|
readonly protocol: "http:";
|
|
201
184
|
} & {
|
|
202
185
|
method: "GET";
|
|
203
186
|
}, (opt: RequestOption, arg: {
|
|
204
|
-
/**附加的查询表单数据 */
|
|
205
187
|
query: QueryRequestData;
|
|
206
|
-
}) => MPromise<SendProcData>, AcceptProcData<
|
|
207
|
-
acceptJson(): UtilHttp<D, S, AcceptProcData<
|
|
188
|
+
}) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
189
|
+
acceptJson(): UtilHttp<D, S, AcceptProcData<RequestResult<JToken> | undefined>>;
|
|
208
190
|
acceptString(): UtilHttp<D, S, typeof AcceptStringProc>;
|
|
209
191
|
acceptNone(): UtilHttp<D, S, typeof AcceptNoneProc>;
|
|
192
|
+
/** 接收并保存为文件 */
|
|
210
193
|
acceptFile(): UtilHttp<D, S, (arg: {
|
|
211
194
|
acceptFilepath: string;
|
|
212
|
-
}) => MPromise<AcceptProcData<{
|
|
213
|
-
promise: Promise<boolean>;
|
|
214
|
-
}, {
|
|
215
|
-
/**响应头 */
|
|
216
|
-
headers: http.IncomingHttpHeaders;
|
|
217
|
-
/**响应状态码 */
|
|
218
|
-
statusCode?: number;
|
|
219
|
-
/**保存文件路径 */
|
|
195
|
+
}) => MPromise<AcceptProcData<RequestResult<{
|
|
220
196
|
filepath: string;
|
|
221
|
-
} | undefined>>>;
|
|
197
|
+
}> | undefined>>>;
|
|
198
|
+
/** 流式接收数据 (如 AI SSE 对话) 返回 AsyncGenerator */
|
|
199
|
+
acceptStream(): UtilHttp<D, S, AcceptProcData<RequestResult<AsyncGenerator<Uint8Array, void, unknown>> | undefined>>;
|
|
222
200
|
/**自定的接收数据类型*/
|
|
223
|
-
acceptRaw<
|
|
201
|
+
acceptRaw<AR, AT extends {}>(proc: AcceptProcCtor<AR, AT>): UtilHttp<D, S, typeof proc>;
|
|
224
202
|
/**发送json
|
|
225
203
|
* 请求参数为 (token:JToken)
|
|
226
204
|
*/
|
|
@@ -229,12 +207,10 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
229
207
|
"Content-Type": "application/json";
|
|
230
208
|
};
|
|
231
209
|
}, (opt: RequestOption, arg: {
|
|
232
|
-
/**发送的json */
|
|
233
210
|
json: JToken;
|
|
234
211
|
}) => MPromise<SendProcData>, A>;
|
|
235
212
|
/**利用 appendQuery 直接将表单附加在path上发送请求 */
|
|
236
213
|
sendQuery(): UtilHttp<D, (opt: RequestOption, arg: {
|
|
237
|
-
/**附加的查询表单数据 */
|
|
238
214
|
query: QueryRequestData;
|
|
239
215
|
}) => MPromise<SendProcData>, A>;
|
|
240
216
|
/**发送表单 */
|
|
@@ -243,19 +219,15 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
243
219
|
"Content-Type": "application/x-www-form-urlencoded";
|
|
244
220
|
};
|
|
245
221
|
}, (opt: RequestOption, arg: {
|
|
246
|
-
/**表单 */
|
|
247
222
|
form: QueryRequestData;
|
|
248
223
|
}) => MPromise<SendProcData>, A>;
|
|
249
224
|
/**发送form-data包提供的表单数据 */
|
|
250
225
|
sendFormData(): UtilHttp<D, (opt: RequestOption, arg: {
|
|
251
|
-
|
|
252
|
-
formdata: FormData;
|
|
226
|
+
formdata: globalThis.FormData;
|
|
253
227
|
}) => MPromise<SendProcData>, A>;
|
|
254
228
|
/**发送文件 */
|
|
255
229
|
sendFile(): UtilHttp<D, (opt: RequestOption, arg: {
|
|
256
|
-
/**文件路径 */
|
|
257
230
|
filepath: string;
|
|
258
|
-
/**文件名 */
|
|
259
231
|
filename?: string;
|
|
260
232
|
}) => MPromise<SendProcData>, A>;
|
|
261
233
|
sendNone(): UtilHttp<D, typeof SendNoneProc, A>;
|
|
@@ -289,7 +261,7 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
|
|
|
289
261
|
* @param reqProc - 请求处理函数 需调用req.end()
|
|
290
262
|
* @param acceptProc - 响应处理数据
|
|
291
263
|
*/
|
|
292
|
-
static request<T>(option: RequestOption, sendProc: SendProcData, acceptProc:
|
|
264
|
+
static request<T>(option: RequestOption, sendProc: SendProcData, acceptProc: AcceptProcData<T>): Promise<T | undefined>;
|
|
293
265
|
/**构建query */
|
|
294
266
|
static buildQuery(base: string, data: QueryRequestData): string;
|
|
295
267
|
}
|
package/dist/UtilHttp.js
CHANGED
|
@@ -5,12 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.UtilHttp = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const http_1 = __importDefault(require("http"));
|
|
9
|
-
const https_1 = __importDefault(require("https"));
|
|
10
8
|
const querystring_1 = __importDefault(require("querystring"));
|
|
9
|
+
const stream_1 = require("stream");
|
|
10
|
+
const promises_1 = require("stream/promises");
|
|
11
11
|
const url_1 = require("url");
|
|
12
12
|
const js_utils_1 = require("@zwa73/js-utils");
|
|
13
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
14
13
|
const pathe_1 = __importDefault(require("pathe"));
|
|
15
14
|
const UtilFunctions_1 = require("./UtilFunctions");
|
|
16
15
|
const UtilLogger_1 = require("./UtilLogger");
|
|
@@ -18,28 +17,33 @@ const RequestDefOption = {
|
|
|
18
17
|
logLevel: 'http',
|
|
19
18
|
timeout: 0,
|
|
20
19
|
};
|
|
21
|
-
const SendNoneProc = {
|
|
22
|
-
proc: req => void req.end()
|
|
23
|
-
};
|
|
20
|
+
const SendNoneProc = {};
|
|
24
21
|
const AcceptStringProc = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
parseResponse: async (response, opt) => {
|
|
23
|
+
try {
|
|
24
|
+
const text = await response.text();
|
|
25
|
+
return {
|
|
26
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
27
|
+
statusCode: response.status,
|
|
28
|
+
data: text
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
UtilLogger_1.SLogger.warn(`accept string 接收反馈错误:`, err);
|
|
30
33
|
return undefined;
|
|
31
34
|
}
|
|
32
|
-
return result;
|
|
33
35
|
}
|
|
34
36
|
};
|
|
35
37
|
const AcceptNoneProc = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
parseResponse: async (response) => {
|
|
39
|
+
// 即使不处理返回值,也建议消费掉 body 释放内存
|
|
40
|
+
if (response.body)
|
|
41
|
+
await response.arrayBuffer();
|
|
42
|
+
return {
|
|
43
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
44
|
+
statusCode: response.status,
|
|
45
|
+
data: undefined
|
|
46
|
+
};
|
|
43
47
|
}
|
|
44
48
|
};
|
|
45
49
|
/**http请求工具 */
|
|
@@ -53,11 +57,9 @@ class UtilHttp {
|
|
|
53
57
|
this._accept = _accept;
|
|
54
58
|
}
|
|
55
59
|
//#region 流式创建
|
|
56
|
-
/**设为https请求 */
|
|
57
60
|
static https() {
|
|
58
61
|
return new UtilHttp({ protocol: 'https:' }, SendNoneProc, AcceptStringProc);
|
|
59
62
|
}
|
|
60
|
-
/**设为http请求 */
|
|
61
63
|
static http() {
|
|
62
64
|
return new UtilHttp({ protocol: 'http:' }, SendNoneProc, AcceptStringProc);
|
|
63
65
|
}
|
|
@@ -111,69 +113,47 @@ class UtilHttp {
|
|
|
111
113
|
//#endregion
|
|
112
114
|
//#region 快速预设
|
|
113
115
|
/**收发皆为json的预设 */
|
|
114
|
-
json() {
|
|
115
|
-
return this.sendJson().acceptJson();
|
|
116
|
-
}
|
|
116
|
+
json() { return this.sendJson().acceptJson(); }
|
|
117
117
|
/**收发皆为json的post预设 */
|
|
118
|
-
postJson() {
|
|
119
|
-
return this.post().json();
|
|
120
|
-
}
|
|
118
|
+
postJson() { return this.post().json(); }
|
|
121
119
|
/**无查询参数获取json的get预设 */
|
|
122
|
-
getJson() {
|
|
123
|
-
return this.get().sendNone().acceptJson();
|
|
124
|
-
}
|
|
120
|
+
getJson() { return this.get().sendNone().acceptJson(); }
|
|
125
121
|
/**有查询参数获取json的get预设 */
|
|
126
|
-
queryJson() {
|
|
127
|
-
return this.get().sendQuery().acceptJson();
|
|
128
|
-
}
|
|
122
|
+
queryJson() { return this.get().sendQuery().acceptJson(); }
|
|
129
123
|
/**收发皆为json的https-post预设 */
|
|
130
|
-
static httpsPostJson() {
|
|
131
|
-
return UtilHttp.https().postJson();
|
|
132
|
-
}
|
|
124
|
+
static httpsPostJson() { return UtilHttp.https().postJson(); }
|
|
133
125
|
/**收发皆为json的http-post预设 */
|
|
134
|
-
static httpPostJson() {
|
|
135
|
-
return UtilHttp.http().postJson();
|
|
136
|
-
}
|
|
126
|
+
static httpPostJson() { return UtilHttp.http().postJson(); }
|
|
137
127
|
/**无查询参数获取json的https-get预设 */
|
|
138
|
-
static httpsGetJson() {
|
|
139
|
-
return UtilHttp.https().getJson();
|
|
140
|
-
}
|
|
128
|
+
static httpsGetJson() { return UtilHttp.https().getJson(); }
|
|
141
129
|
/**有查询参数获取json的https-get预设 */
|
|
142
|
-
static httpsQueryJson() {
|
|
143
|
-
return UtilHttp.http().queryJson();
|
|
144
|
-
}
|
|
130
|
+
static httpsQueryJson() { return UtilHttp.http().queryJson(); }
|
|
145
131
|
/**无查询参数获取json的http-get预设 */
|
|
146
|
-
static httpGetJson() {
|
|
147
|
-
return UtilHttp.http().getJson();
|
|
148
|
-
}
|
|
132
|
+
static httpGetJson() { return UtilHttp.http().getJson(); }
|
|
149
133
|
/**有查询参数获取json的http-get预设 */
|
|
150
|
-
static httpQueryJson() {
|
|
151
|
-
return UtilHttp.http().queryJson();
|
|
152
|
-
}
|
|
134
|
+
static httpQueryJson() { return UtilHttp.http().queryJson(); }
|
|
153
135
|
//#endregion
|
|
154
136
|
//#region 接收数据类型
|
|
155
137
|
acceptJson() {
|
|
156
138
|
const acceptProc = {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
UtilLogger_1.SLogger.warn(`accept json 接收反馈错误: 原始字符串为空`, UtilFunctions_1.UtilFunc.stringifyJToken(result, { compress: true, space: 2 }));
|
|
167
|
-
return { ...result, raw: "", data: null };
|
|
139
|
+
parseResponse: async (response, opt) => {
|
|
140
|
+
const text = await response.text();
|
|
141
|
+
const rest = {
|
|
142
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
143
|
+
statusCode: response.status
|
|
144
|
+
};
|
|
145
|
+
if (text.trim() == "") {
|
|
146
|
+
UtilLogger_1.SLogger.warn(`accept json 接收反馈错误: 原始字符串为空`);
|
|
147
|
+
return { ...rest, raw: "", data: null };
|
|
168
148
|
}
|
|
169
149
|
try {
|
|
170
|
-
const obj = JSON.parse(
|
|
171
|
-
UtilLogger_1.SLogger.log(opt.logLevel ?? 'none', `accept json 接受信息 data:`, UtilFunctions_1.UtilFunc.stringifyJToken(obj, { compress: true, space: 2 })
|
|
150
|
+
const obj = JSON.parse(text.trim());
|
|
151
|
+
UtilLogger_1.SLogger.log(opt.logLevel ?? 'none', `accept json 接受信息 data:`, UtilFunctions_1.UtilFunc.stringifyJToken(obj, { compress: true, space: 2 }));
|
|
172
152
|
return { ...rest, data: obj };
|
|
173
153
|
}
|
|
174
154
|
catch (err) {
|
|
175
|
-
UtilLogger_1.SLogger.warn(`accept json
|
|
176
|
-
return { ...
|
|
155
|
+
UtilLogger_1.SLogger.warn(`accept json 解析错误:`, err, text);
|
|
156
|
+
return { ...rest, raw: text, data: null };
|
|
177
157
|
}
|
|
178
158
|
}
|
|
179
159
|
};
|
|
@@ -188,36 +168,61 @@ class UtilHttp {
|
|
|
188
168
|
this._accept = AcceptNoneProc;
|
|
189
169
|
return this;
|
|
190
170
|
}
|
|
171
|
+
/** 接收并保存为文件 */
|
|
191
172
|
acceptFile() {
|
|
192
173
|
const acceptProc = (arg) => ({
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
fileStream.on('error', err => {
|
|
197
|
-
UtilLogger_1.SLogger.warn(`accept file 文件流写入错误:`, err);
|
|
198
|
-
resolve(false); // 标记写入已结束, 但失败
|
|
199
|
-
});
|
|
200
|
-
fileStream.on('finish', () => {
|
|
201
|
-
resolve(true); // 标记写入成功
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
res.pipe(fileStream);
|
|
205
|
-
return { promise: fileWritePromise };
|
|
206
|
-
},
|
|
207
|
-
parse: async (result) => {
|
|
208
|
-
if (result == undefined) {
|
|
209
|
-
UtilLogger_1.SLogger.warn(`accept file 接收反馈错误: 响应结果无效`);
|
|
174
|
+
parseResponse: async (response) => {
|
|
175
|
+
if (!response.body) {
|
|
176
|
+
UtilLogger_1.SLogger.warn(`accept file 接收反馈错误: 响应结果无 body`);
|
|
210
177
|
return undefined;
|
|
211
178
|
}
|
|
212
|
-
|
|
213
|
-
|
|
179
|
+
try {
|
|
180
|
+
const fileStream = fs_1.default.createWriteStream(arg.acceptFilepath);
|
|
181
|
+
// Node 20 特性:将 Web ReadableStream 转换为 Node Stream
|
|
182
|
+
const readable = stream_1.Readable.fromWeb(response.body);
|
|
183
|
+
readable.pipe(fileStream);
|
|
184
|
+
// 等待流写入完成
|
|
185
|
+
await (0, promises_1.finished)(fileStream);
|
|
186
|
+
return {
|
|
187
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
188
|
+
statusCode: response.status,
|
|
189
|
+
data: { filepath: arg.acceptFilepath }
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
UtilLogger_1.SLogger.warn(`accept file 文件流写入错误:`, err);
|
|
214
194
|
return undefined;
|
|
215
|
-
|
|
195
|
+
}
|
|
216
196
|
}
|
|
217
197
|
});
|
|
218
198
|
this._accept = acceptProc;
|
|
219
199
|
return this;
|
|
220
200
|
}
|
|
201
|
+
/** 流式接收数据 (如 AI SSE 对话) 返回 AsyncGenerator */
|
|
202
|
+
acceptStream() {
|
|
203
|
+
const acceptProc = {
|
|
204
|
+
parseResponse: async (response) => {
|
|
205
|
+
if (response.body == null) {
|
|
206
|
+
UtilLogger_1.SLogger.warn(`accept stream 接收反馈错误: 响应结果无 body`);
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
const notnullBody = response.body;
|
|
210
|
+
// Node 20 允许直接异步迭代 Web Stream
|
|
211
|
+
const generator = async function* () {
|
|
212
|
+
for await (const chunk of notnullBody) {
|
|
213
|
+
yield chunk;
|
|
214
|
+
}
|
|
215
|
+
}();
|
|
216
|
+
return {
|
|
217
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
218
|
+
statusCode: response.status,
|
|
219
|
+
data: generator
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
this._accept = acceptProc;
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
221
226
|
/**自定的接收数据类型*/
|
|
222
227
|
acceptRaw(proc) {
|
|
223
228
|
this._accept = proc;
|
|
@@ -229,23 +234,10 @@ class UtilHttp {
|
|
|
229
234
|
* 请求参数为 (token:JToken)
|
|
230
235
|
*/
|
|
231
236
|
sendJson() {
|
|
232
|
-
const sendProc = (opt, arg) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this._data.headers ??= {};
|
|
237
|
-
this._data.headers['Content-Length'] = Buffer.byteLength(data);
|
|
238
|
-
return {
|
|
239
|
-
proc: async (req) => {
|
|
240
|
-
if (isPost) {
|
|
241
|
-
const flushed = req.write(data);
|
|
242
|
-
if (!flushed)
|
|
243
|
-
await new Promise((resolve) => req.once('drain', resolve));
|
|
244
|
-
}
|
|
245
|
-
req.end();
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
};
|
|
237
|
+
const sendProc = (opt, arg) => ({
|
|
238
|
+
body: JSON.stringify(arg.json),
|
|
239
|
+
headers: { 'Content-Type': 'application/json' }
|
|
240
|
+
});
|
|
249
241
|
this._send = sendProc;
|
|
250
242
|
this._data.headers ??= {};
|
|
251
243
|
this._data.headers['Content-Type'] = 'application/json';
|
|
@@ -255,33 +247,21 @@ class UtilHttp {
|
|
|
255
247
|
sendQuery() {
|
|
256
248
|
const sendProc = (opt, arg) => {
|
|
257
249
|
opt.path = UtilHttp.buildQuery(opt.path ?? '', arg.query);
|
|
258
|
-
return {
|
|
259
|
-
proc: req => void req.end()
|
|
260
|
-
};
|
|
250
|
+
return {};
|
|
261
251
|
};
|
|
262
252
|
this._send = sendProc;
|
|
263
253
|
return this;
|
|
264
254
|
}
|
|
265
255
|
/**发送表单 */
|
|
266
256
|
sendForm() {
|
|
267
|
-
const
|
|
268
|
-
const { method } = opt;
|
|
269
|
-
const isPost = (method == "POST");
|
|
257
|
+
const sendProc = (opt, arg) => {
|
|
270
258
|
const data = querystring_1.default.stringify(arg.form);
|
|
271
|
-
this._data.headers ??= {};
|
|
272
|
-
this._data.headers['Content-Length'] = Buffer.byteLength(data);
|
|
273
259
|
return {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const flushed = req.write(data);
|
|
277
|
-
if (!flushed)
|
|
278
|
-
await new Promise((resolve) => req.once('drain', resolve));
|
|
279
|
-
}
|
|
280
|
-
req.end();
|
|
281
|
-
}
|
|
260
|
+
body: data,
|
|
261
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
282
262
|
};
|
|
283
263
|
};
|
|
284
|
-
this._send =
|
|
264
|
+
this._send = sendProc;
|
|
285
265
|
this._data.headers ??= {};
|
|
286
266
|
this._data.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
287
267
|
return this;
|
|
@@ -289,19 +269,9 @@ class UtilHttp {
|
|
|
289
269
|
/**发送form-data包提供的表单数据 */
|
|
290
270
|
sendFormData() {
|
|
291
271
|
const sendProc = (opt, arg) => {
|
|
292
|
-
const { method } = opt;
|
|
293
|
-
const isPost = (method == "POST");
|
|
294
|
-
opt.headers = {
|
|
295
|
-
...arg.formdata.getHeaders(),
|
|
296
|
-
...opt.headers,
|
|
297
|
-
};
|
|
298
272
|
return {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
arg.formdata.pipe(req);
|
|
302
|
-
else
|
|
303
|
-
req.end();
|
|
304
|
-
}
|
|
273
|
+
body: arg.formdata
|
|
274
|
+
// 注意:绝对不要在这里手动设置 Content-Type,fetch 会自动设置并附带正确的 boundary
|
|
305
275
|
};
|
|
306
276
|
};
|
|
307
277
|
this._send = sendProc;
|
|
@@ -309,25 +279,14 @@ class UtilHttp {
|
|
|
309
279
|
}
|
|
310
280
|
/**发送文件 */
|
|
311
281
|
sendFile() {
|
|
312
|
-
const proc = (opt, arg) => {
|
|
313
|
-
const { method } = opt;
|
|
314
|
-
const isPost = (method == "POST");
|
|
282
|
+
const proc = async (opt, arg) => {
|
|
315
283
|
let { filepath, filename } = arg;
|
|
316
|
-
const formData = new form_data_1.default();
|
|
317
284
|
filename = filename ?? pathe_1.default.basename(filepath);
|
|
318
|
-
formData
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
};
|
|
323
|
-
return {
|
|
324
|
-
proc: req => {
|
|
325
|
-
if (isPost)
|
|
326
|
-
formData.pipe(req);
|
|
327
|
-
else
|
|
328
|
-
req.end();
|
|
329
|
-
}
|
|
330
|
-
};
|
|
285
|
+
const formData = new globalThis.FormData();
|
|
286
|
+
// Node 19.8+ 支持 openAsBlob,零内存拷贝读取文件为 Blob 格式
|
|
287
|
+
const fileBlob = await fs_1.default.openAsBlob(filepath);
|
|
288
|
+
formData.append(filename, fileBlob, filename);
|
|
289
|
+
return { body: formData };
|
|
331
290
|
};
|
|
332
291
|
this._send = proc;
|
|
333
292
|
return this;
|
|
@@ -347,14 +306,10 @@ class UtilHttp {
|
|
|
347
306
|
*/
|
|
348
307
|
async once(arg) {
|
|
349
308
|
const fullopt = UtilFunctions_1.UtilFunc.assignOption(RequestDefOption, { ...this._data, ...arg.option ?? {} });
|
|
350
|
-
const sendProc = typeof this._send === 'function'
|
|
351
|
-
|
|
352
|
-
: this._send;
|
|
353
|
-
const { parse, ...acceptProc } = typeof this._accept === 'function'
|
|
354
|
-
? await this._accept(arg)
|
|
355
|
-
: this._accept;
|
|
309
|
+
const sendProc = typeof this._send === 'function' ? await this._send(fullopt, arg) : this._send;
|
|
310
|
+
const acceptProc = typeof this._accept === 'function' ? await this._accept(arg) : this._accept;
|
|
356
311
|
const res = await UtilHttp.request(fullopt, sendProc, acceptProc);
|
|
357
|
-
return
|
|
312
|
+
return res;
|
|
358
313
|
}
|
|
359
314
|
/**重复发送网络请求
|
|
360
315
|
* @param verify - 有效性验证函数
|
|
@@ -376,106 +331,65 @@ class UtilHttp {
|
|
|
376
331
|
* @param acceptProc - 响应处理数据
|
|
377
332
|
*/
|
|
378
333
|
static async request(option, sendProc, acceptProc) {
|
|
379
|
-
const {
|
|
380
|
-
const {
|
|
381
|
-
|
|
382
|
-
const {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const
|
|
387
|
-
let
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
mergedata = await reqReduce(mergedata, chunk);
|
|
424
|
-
}
|
|
425
|
-
catch (err) {
|
|
426
|
-
UtilLogger_1.SLogger.error(`${flagName} reduce函数错误:`, err, `chunk:${chunk}\nmergedata:`, mergedata);
|
|
427
|
-
finallyResolve(undefined);
|
|
428
|
-
}
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
res.on('error', err => {
|
|
433
|
-
UtilLogger_1.SLogger.warn(`${flagName} 接收反馈错误:`, err);
|
|
434
|
-
finallyResolve(undefined);
|
|
435
|
-
});
|
|
436
|
-
res.on('end', async () => {
|
|
437
|
-
await dataPromise;
|
|
438
|
-
finallyResolve({
|
|
439
|
-
headers: res.headers,
|
|
440
|
-
statusCode: res.statusCode,
|
|
441
|
-
data: mergedata,
|
|
442
|
-
});
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
catch (err) {
|
|
446
|
-
UtilLogger_1.SLogger.warn(`${flagName} 未知错误:`, err);
|
|
447
|
-
finallyResolve(undefined);
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
//路由 http/https
|
|
452
|
-
const req = protocol == "https:"
|
|
453
|
-
? https_1.default.request(baseReqOpt, resFunc)
|
|
454
|
-
: http_1.default.request(baseReqOpt, resFunc);
|
|
455
|
-
//请求超时
|
|
456
|
-
if (hasTimeLimit) {
|
|
457
|
-
req.setTimeout(timeout, () => {
|
|
458
|
-
UtilLogger_1.SLogger.warn(`${flagName} http.request 触发 ${timeout} ms 超时, 继续挂起等待`);
|
|
459
|
-
});
|
|
334
|
+
const { protocol, hostname, port, path: reqPath, method, timeout, headers: baseHeaders, signal, dispatcher } = option;
|
|
335
|
+
const { body, headers: extraHeaders } = sendProc;
|
|
336
|
+
const portStr = port ? `:${port}` : '';
|
|
337
|
+
const url = `${protocol}//${hostname}${portStr}${reqPath ?? ''}`;
|
|
338
|
+
const flagName = `UtilHttp.fetch ${method} ${url}`;
|
|
339
|
+
// === 信号与超时逻辑 ===
|
|
340
|
+
let finalSignal = signal;
|
|
341
|
+
const hasTimeLimit = timeout && timeout >= 10_000;
|
|
342
|
+
let timeoutId;
|
|
343
|
+
// 如果外部没有传 signal,并且设置了合法的 timeout,我们才自己建一个 controller
|
|
344
|
+
if (finalSignal == null && hasTimeLimit) {
|
|
345
|
+
const controller = new AbortController();
|
|
346
|
+
finalSignal = controller.signal;
|
|
347
|
+
timeoutId = setTimeout(() => {
|
|
348
|
+
UtilLogger_1.SLogger.warn(`${flagName} 触发 ${timeout} ms 超时, 取消请求`);
|
|
349
|
+
controller.abort();
|
|
350
|
+
}, timeout);
|
|
351
|
+
}
|
|
352
|
+
// 将可能含有 number 的 Header 对象标准化为 fetch 接受的 Record<string, string>
|
|
353
|
+
const fetchHeaders = Object.fromEntries(Object
|
|
354
|
+
.entries({ ...baseHeaders, ...extraHeaders })
|
|
355
|
+
.map(([k, v]) => {
|
|
356
|
+
if (v == undefined)
|
|
357
|
+
return undefined;
|
|
358
|
+
if (typeof v != 'string')
|
|
359
|
+
return [k, String(v)];
|
|
360
|
+
return [k, v];
|
|
361
|
+
}).filter(v => v != undefined));
|
|
362
|
+
// 构建 fetch 的初始配置
|
|
363
|
+
const fetchOptions = {
|
|
364
|
+
method, body, dispatcher,
|
|
365
|
+
headers: fetchHeaders,
|
|
366
|
+
signal: finalSignal,
|
|
367
|
+
};
|
|
368
|
+
try {
|
|
369
|
+
const response = await fetch(url, fetchOptions);
|
|
370
|
+
if (timeoutId)
|
|
371
|
+
clearTimeout(timeoutId);
|
|
372
|
+
// 将 response 移交给具体的 Accept 策略解析 (JSON / 文本 / 写入流等)
|
|
373
|
+
return await acceptProc.parseResponse(response, option);
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
if (UtilFunctions_1.UtilFunc.checkSharpSchema(err, { name: 'string' }) && err.name === 'AbortError') {
|
|
377
|
+
UtilLogger_1.SLogger.warn(`${flagName} 请求被终止 (超时)`);
|
|
460
378
|
}
|
|
461
|
-
|
|
379
|
+
else {
|
|
462
380
|
UtilLogger_1.SLogger.warn(`${flagName} 发送请求错误:`, err);
|
|
463
|
-
finallyResolve(undefined);
|
|
464
|
-
});
|
|
465
|
-
try {
|
|
466
|
-
await reqProc(req);
|
|
467
|
-
}
|
|
468
|
-
catch (err) {
|
|
469
|
-
UtilLogger_1.SLogger.error(`${flagName} proc函数错误:`, err);
|
|
470
|
-
finallyResolve(undefined);
|
|
471
381
|
}
|
|
472
|
-
|
|
382
|
+
return undefined;
|
|
383
|
+
}
|
|
384
|
+
finally {
|
|
385
|
+
if (timeoutId)
|
|
386
|
+
clearTimeout(timeoutId);
|
|
387
|
+
}
|
|
473
388
|
}
|
|
474
389
|
/**构建query */
|
|
475
390
|
static buildQuery(base, data) {
|
|
476
391
|
const queryString = querystring_1.default.stringify(data);
|
|
477
392
|
if (queryString) {
|
|
478
|
-
// 检查当前路径是否已经包含问号
|
|
479
393
|
const separator = base.includes('?') ? '&' : '?';
|
|
480
394
|
base += separator + queryString;
|
|
481
395
|
}
|
|
@@ -501,25 +415,19 @@ if (false)
|
|
|
501
415
|
const sj = await tool.clone()
|
|
502
416
|
.sendJson()
|
|
503
417
|
.acceptJson()
|
|
504
|
-
.once({
|
|
505
|
-
json: { test: 1 },
|
|
506
|
-
});
|
|
418
|
+
.once({ json: { test: 1 }, });
|
|
507
419
|
console.log(sj);
|
|
508
420
|
//form
|
|
509
421
|
const sf = await tool.clone()
|
|
510
422
|
.sendForm()
|
|
511
423
|
.acceptJson()
|
|
512
|
-
.once({
|
|
513
|
-
form: { test: 1 }
|
|
514
|
-
});
|
|
424
|
+
.once({ form: { test: 1 } });
|
|
515
425
|
console.log(sf);
|
|
516
426
|
//query
|
|
517
427
|
const sq = await tool.clone()
|
|
518
428
|
.sendQuery()
|
|
519
429
|
.acceptJson()
|
|
520
|
-
.once({
|
|
521
|
-
query: { test: 1 }
|
|
522
|
-
});
|
|
430
|
+
.once({ query: { test: 1 } });
|
|
523
431
|
console.log(sq);
|
|
524
432
|
const filepath = pathe_1.default.join(__dirname, '..', 'input.wav');
|
|
525
433
|
//formData
|
|
@@ -533,8 +441,29 @@ if (false)
|
|
|
533
441
|
const sfile = await tool.clone()
|
|
534
442
|
.sendFile()
|
|
535
443
|
.acceptJson()
|
|
536
|
-
.once({
|
|
537
|
-
filepath: filepath
|
|
538
|
-
});
|
|
444
|
+
.once({ filepath: filepath });
|
|
539
445
|
console.log(sfile);
|
|
540
446
|
})());
|
|
447
|
+
if (false)
|
|
448
|
+
void (async () => {
|
|
449
|
+
console.log("=== 测试代理功能 ===");
|
|
450
|
+
// 基础测试工具
|
|
451
|
+
const tool = UtilHttp.url('https://httpbin.org/ip').getJson().option({ timeout: 10000 });
|
|
452
|
+
// 1. 测试直连 IP
|
|
453
|
+
console.log("正在测试直连...");
|
|
454
|
+
const directRes = await tool.clone().once({});
|
|
455
|
+
console.log("【直连 IP 结果】:", directRes?.data);
|
|
456
|
+
// 2. 测试代理 IP
|
|
457
|
+
// 请将下面的地址换成你本地实际的代理软件端口(比如 Clash 默认通常是 7890,v2ray 是 10809)
|
|
458
|
+
//const proxyUrl = 'http://127.0.0.1:7890';
|
|
459
|
+
//console.log(`\n正在测试代理 (${proxyUrl})...`);
|
|
460
|
+
//const proxyRes = await tool.clone()
|
|
461
|
+
// .option({ proxy: proxyUrl })
|
|
462
|
+
// .once({});
|
|
463
|
+
//
|
|
464
|
+
//if (proxyRes?.data) {
|
|
465
|
+
// console.log("【代理 IP 结果】:", proxyRes.data);
|
|
466
|
+
//} else {
|
|
467
|
+
// console.log("【代理请求失败】: 请检查代理软件是否运行,以及端口是否正确。");
|
|
468
|
+
//}
|
|
469
|
+
})();
|
package/dist/UtilInterfaces.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { JToken, JValue, JArray, JObject, IJData, AnyFunc, Keyable, DeepReadonly, DeepWritable, PartialOption, ProperSubset, ProperSubsetCheck, IncludeCheck, UnionCheck, Literal, LiteralCheck, AllExtends, AssignObject, Writeable, Requireify, Inverted, FixedLengthTuple, Increment, RangeTuple, AnyString, UnionToIntersection, ExclusiveRecord, ExclusiveJObject, PromiseStatus, StatusVerifyFn, Await, FuncPropNames, ExtendThen, RequiredOnly, WithPrefix, Outcome, Either, Matchable, MatchableFlag, ExtractOutcome, ExtractMatchable, NeedInit, PRecord, MPromise, SPromise, SMPromise, NotPromise, AnyRecord, ReturnTypeOrNever, CmtTuple, Flasy, SrtSegment, ILogger, LogLevel, Asyncize, SharpSchema, ExpandSharpSchema, Preset, PresetOption, PresetFinal, NotFunc, MFunc, MReturnType, IoCDepTable, IoCDepCtorRtn, IoCDepCtor, StaticClass } from "@zwa73/js-utils";
|
|
1
|
+
export type { JToken, JValue, JArray, JObject, IJData, AnyFunc, Keyable, DeepReadonly, DeepWritable, PartialOption, ProperSubset, ProperSubsetCheck, IncludeCheck, UnionCheck, Literal, LiteralCheck, AllExtends, AssignObject, Writeable, Requireify, Inverted, FixedLengthTuple, Increment, RangeTuple, AnyString, UnionToIntersection, ExclusiveRecord, ExclusiveJObject, PromiseStatus, StatusVerifyFn, Await, FuncPropNames, ExtendThen, RequiredOnly, WithPrefix, Outcome, Either, Matchable, MatchableFlag, ExtractOutcome, ExtractMatchable, NeedInit, PRecord, MPromise, SPromise, SMPromise, NotPromise, AnyRecord, ReturnTypeOrNever, CmtTuple, Flasy, SrtSegment, ILogger, LogLevel, ILoggerFull, Asyncize, SharpSchema, ExpandSharpSchema, Preset, PresetOption, PresetFinal, NotFunc, MFunc, MReturnType, IoCDepTable, IoCDepCtorRtn, IoCDepCtor, StaticClass } from "@zwa73/js-utils";
|
|
2
2
|
export type { StringifyOpt, PromiseRetries, PromiseRetryResult } from "@zwa73/js-utils";
|
package/dist/UtilLogger.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ILogger, ILoggerFull } from '@zwa73/js-utils';
|
|
1
2
|
import type { LogLevel } from './UtilInterfaces';
|
|
2
3
|
/**hrtime所产生的的记录 */
|
|
3
4
|
export type HRTimeLog = {
|
|
@@ -11,12 +12,12 @@ export declare class SLogger {
|
|
|
11
12
|
* @param name - logger的名称 默认default
|
|
12
13
|
* @returns 获取的logger
|
|
13
14
|
*/
|
|
14
|
-
static getLogger(name?: string):
|
|
15
|
+
static getLogger(name?: string): ILoggerFull;
|
|
15
16
|
/**创建Logger
|
|
16
|
-
* @param opt -
|
|
17
|
-
* @returns
|
|
17
|
+
* @param opt - ILogger 实例或创建参数
|
|
18
|
+
* @returns ILogger
|
|
18
19
|
*/
|
|
19
|
-
static createLogger(opt?: {
|
|
20
|
+
static createLogger(opt?: ILogger | {
|
|
20
21
|
/**logger的名称 默认default */
|
|
21
22
|
name?: string;
|
|
22
23
|
/**输出到控制台的最低等级 默认info */
|
|
@@ -25,7 +26,7 @@ export declare class SLogger {
|
|
|
25
26
|
outFloder?: string;
|
|
26
27
|
/**输出到文件的最低等级 默认info */
|
|
27
28
|
fileLevel?: LogLevel;
|
|
28
|
-
}):
|
|
29
|
+
}): ILogger;
|
|
29
30
|
private constructor();
|
|
30
31
|
private _logger;
|
|
31
32
|
/**记录Logger的表 */
|
|
@@ -96,52 +97,52 @@ export declare class SLogger {
|
|
|
96
97
|
* @param messages - log消息
|
|
97
98
|
* @returns 自身
|
|
98
99
|
*/
|
|
99
|
-
static log(level: LogLevel, ...messages: any[]):
|
|
100
|
+
static log(level: LogLevel, ...messages: any[]): ILoggerFull;
|
|
100
101
|
/**让名称为default的logger 产生一条fatal等级的log 返回自身
|
|
101
102
|
* @param messages - log消息
|
|
102
103
|
* @returns 自身
|
|
103
104
|
*/
|
|
104
|
-
static fatal(...messages: any[]):
|
|
105
|
+
static fatal(...messages: any[]): ILoggerFull;
|
|
105
106
|
/**让名称为default的logger 产生一条error等级的log 返回自身
|
|
106
107
|
* @param messages - log消息
|
|
107
108
|
* @returns 自身
|
|
108
109
|
*/
|
|
109
|
-
static error(...messages: any[]):
|
|
110
|
+
static error(...messages: any[]): ILoggerFull;
|
|
110
111
|
/**让名称为default的logger 产生一条warn等级的log 返回自身
|
|
111
112
|
* @param messages - log消息
|
|
112
113
|
* @returns 自身
|
|
113
114
|
*/
|
|
114
|
-
static warn(...messages: any[]):
|
|
115
|
+
static warn(...messages: any[]): ILoggerFull;
|
|
115
116
|
/**让名称为default的logger 产生一条info等级的log 返回自身
|
|
116
117
|
* @param messages - log消息
|
|
117
118
|
* @returns 自身
|
|
118
119
|
*/
|
|
119
|
-
static info(...messages: any[]):
|
|
120
|
+
static info(...messages: any[]): ILoggerFull;
|
|
120
121
|
/**让名称为default的logger 产生一条http等级的log 返回自身
|
|
121
122
|
* @param messages - log消息
|
|
122
123
|
* @returns 自身
|
|
123
124
|
*/
|
|
124
|
-
static http(...messages: any[]):
|
|
125
|
+
static http(...messages: any[]): ILoggerFull;
|
|
125
126
|
/**让名称为default的logger 产生一条verbose等级的log 返回自身
|
|
126
127
|
* @param messages - log消息
|
|
127
128
|
* @returns 自身
|
|
128
129
|
*/
|
|
129
|
-
static verbose(...messages: any[]):
|
|
130
|
+
static verbose(...messages: any[]): ILoggerFull;
|
|
130
131
|
/**让名称为default的logger 产生一条debug等级的log 返回自身
|
|
131
132
|
* @param messages - log消息
|
|
132
133
|
* @returns 自身
|
|
133
134
|
*/
|
|
134
|
-
static debug(...messages: any[]):
|
|
135
|
+
static debug(...messages: any[]): ILoggerFull;
|
|
135
136
|
/**让名称为default的logger 产生一条silly等级的log 返回自身
|
|
136
137
|
* @param messages - log消息
|
|
137
138
|
* @returns 自身
|
|
138
139
|
*/
|
|
139
|
-
static silly(...messages: any[]):
|
|
140
|
+
static silly(...messages: any[]): ILoggerFull;
|
|
140
141
|
/**让名称为default的logger 记录当前时间戳并存入表
|
|
141
142
|
* @param flag - 记录的命名
|
|
142
143
|
* @returns 记录的时间
|
|
143
144
|
*/
|
|
144
|
-
static time(flag: string):
|
|
145
|
+
static time(flag: string): void;
|
|
145
146
|
/**让名称为default的logger 根据之前记录的时间戳计算经过的时间 并输出log
|
|
146
147
|
* @param flag - 记录的命名
|
|
147
148
|
* @param level - log等级
|
package/dist/UtilLogger.js
CHANGED
|
@@ -28,6 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.SLogger = void 0;
|
|
30
30
|
const util_1 = require("util");
|
|
31
|
+
const js_utils_1 = require("@zwa73/js-utils");
|
|
31
32
|
const pathe_1 = __importDefault(require("pathe"));
|
|
32
33
|
const winston = __importStar(require("winston"));
|
|
33
34
|
const winston_daily_rotate_file_1 = __importDefault(require("winston-daily-rotate-file"));
|
|
@@ -59,11 +60,32 @@ class SLogger {
|
|
|
59
60
|
return SLogger.loggerTable[name] ?? SLogger.createLogger({ name });
|
|
60
61
|
}
|
|
61
62
|
/**创建Logger
|
|
62
|
-
* @param opt -
|
|
63
|
-
* @returns
|
|
63
|
+
* @param opt - ILogger 实例或创建参数
|
|
64
|
+
* @returns ILogger
|
|
64
65
|
*/
|
|
65
66
|
static createLogger(opt) {
|
|
66
|
-
const
|
|
67
|
+
const tryDestory = (ilogger) => {
|
|
68
|
+
if (ilogger != null && ilogger._logger?.transports) {
|
|
69
|
+
const slogger = ilogger;
|
|
70
|
+
slogger._logger.transports.forEach(tp => {
|
|
71
|
+
if (tp.close != null)
|
|
72
|
+
tp.close();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
// —— 情况一:传入的是 ILogger 实例 ——
|
|
77
|
+
if (opt && 'log' in opt && typeof opt.log === 'function') {
|
|
78
|
+
const externalLogger = opt;
|
|
79
|
+
const key = "default";
|
|
80
|
+
const wrapper = js_utils_1.JsFunc.wrapILogger(externalLogger);
|
|
81
|
+
// 析构旧的
|
|
82
|
+
tryDestory(SLogger.loggerTable[key]);
|
|
83
|
+
// 直接存入 table
|
|
84
|
+
SLogger.loggerTable[key] = wrapper;
|
|
85
|
+
return wrapper;
|
|
86
|
+
}
|
|
87
|
+
// —— 情况二:使用内置 winston ——(原有逻辑)
|
|
88
|
+
const { name = "default", consoleLevel = "info", outFloder, fileLevel = "info" } = (opt ?? {});
|
|
67
89
|
const transports = [];
|
|
68
90
|
if (outFloder != null) {
|
|
69
91
|
const fileFormat = winston.format.combine(winston.format.timestamp({ format: 'HH:mm:ss' }), winston.format.printf((info) => {
|
|
@@ -112,10 +134,13 @@ class SLogger {
|
|
|
112
134
|
out._logger = logger;
|
|
113
135
|
if (SLogger.loggerTable[name] != null) {
|
|
114
136
|
let old = SLogger.loggerTable[name];
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
// 只有 SLogger 实例有 _logger.transports
|
|
138
|
+
if (old._logger?.transports) {
|
|
139
|
+
old._logger.transports.forEach((tp) => {
|
|
140
|
+
if (tp.close != null)
|
|
141
|
+
tp.close();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
119
144
|
}
|
|
120
145
|
SLogger.loggerTable[name] = out;
|
|
121
146
|
return out;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zwa73/utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.295",
|
|
4
4
|
"description": "my utils",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@zwa73/js-utils": "*",
|
|
20
20
|
"@zwa73/modular-mixer": "^1.0.8",
|
|
21
|
-
"form-data": "^4.0.2",
|
|
22
21
|
"glob": "^13.0.0",
|
|
23
22
|
"html-entities": "^2.3.3",
|
|
24
23
|
"pathe": "^1.1.2",
|
|
@@ -62,6 +61,7 @@
|
|
|
62
61
|
"tiktoken": "^1.0.7",
|
|
63
62
|
"tsc-alias": "^1.8.8",
|
|
64
63
|
"typescript": "^5.3.3",
|
|
64
|
+
"undici": "^6.24.1",
|
|
65
65
|
"yaml": "^2.8.1"
|
|
66
66
|
},
|
|
67
67
|
"files": [
|