@zwa73/utils 1.0.293 → 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.
@@ -1,4 +1,4 @@
1
1
  import { UtilFT } from "./UtilFileTools";
2
- export declare const outcome: typeof import("@zwa73/js-utils").JsFunc.outcome, extractOutcome: typeof import("@zwa73/js-utils").JsFunc.extractOutcome, success: typeof import("@zwa73/js-utils").JsFunc.success, failed: typeof import("@zwa73/js-utils").JsFunc.failed, match: typeof import("@zwa73/js-utils").JsFunc.match, isSafeNumber: typeof import("@zwa73/js-utils").JsFunc.isSafeNumber, checkType: typeof import("@zwa73/js-utils").JsFunc.checkType, checkLiteral: typeof import("@zwa73/js-utils").JsFunc.checkLiteral, assertType: typeof import("@zwa73/js-utils").JsFunc.assertType, deepClone: typeof import("@zwa73/js-utils").JsFunc.deepClone, sleep: typeof import("@zwa73/js-utils").JsFunc.sleep, stringifyJToken: typeof import("@zwa73/js-utils").JsFunc.stringifyJToken, getTime: typeof import("@zwa73/js-utils").JsFunc.getTime, mapEntries: typeof import("@zwa73/js-utils").JsFunc.mapEntries, dedent: typeof import("@zwa73/js-utils").JsFunc.dedent, throwError: typeof import("@zwa73/js-utils").JsFunc.throwError, eitherize: typeof import("@zwa73/js-utils").JsFunc.eitherize, memoize: typeof import("@zwa73/js-utils").JsFunc.memoize, lazyFunction: typeof import("@zwa73/js-utils").JsFunc.lazyFunction, ivk: typeof import("@zwa73/js-utils").JsFunc.ivk, l2s: typeof import("@zwa73/js-utils").JsFunc.l2s, s2l: typeof import("@zwa73/js-utils").JsFunc.s2l, structEqual: typeof import("@zwa73/js-utils").JsFunc.structEqual, range: typeof import("@zwa73/js-utils").JsFunc.range, preset: typeof import("@zwa73/js-utils").JsFunc.preset, assignOption: typeof import("@zwa73/js-utils").JsFunc.assignOption;
2
+ export declare const outcome: typeof import("@zwa73/js-utils").JsFunc.outcome, extractOutcome: typeof import("@zwa73/js-utils").JsFunc.extractOutcome, success: typeof import("@zwa73/js-utils").JsFunc.success, failed: typeof import("@zwa73/js-utils").JsFunc.failed, match: typeof import("@zwa73/js-utils").JsFunc.match, isSafeNumber: typeof import("@zwa73/js-utils").JsFunc.isSafeNumber, constrainType: typeof import("@zwa73/js-utils").JsFunc.constrainType, constrainLiteral: typeof import("@zwa73/js-utils").JsFunc.constrainLiteral, assertType: typeof import("@zwa73/js-utils").JsFunc.assertType, deepClone: typeof import("@zwa73/js-utils").JsFunc.deepClone, sleep: typeof import("@zwa73/js-utils").JsFunc.sleep, stringifyJToken: typeof import("@zwa73/js-utils").JsFunc.stringifyJToken, getTime: typeof import("@zwa73/js-utils").JsFunc.getTime, mapEntries: typeof import("@zwa73/js-utils").JsFunc.mapEntries, dedent: typeof import("@zwa73/js-utils").JsFunc.dedent, throwError: typeof import("@zwa73/js-utils").JsFunc.throwError, eitherize: typeof import("@zwa73/js-utils").JsFunc.eitherize, memoize: typeof import("@zwa73/js-utils").JsFunc.memoize, lazyFunction: typeof import("@zwa73/js-utils").JsFunc.lazyFunction, ivk: typeof import("@zwa73/js-utils").JsFunc.ivk, l2s: typeof import("@zwa73/js-utils").JsFunc.l2s, s2l: typeof import("@zwa73/js-utils").JsFunc.s2l, structEqual: typeof import("@zwa73/js-utils").JsFunc.structEqual, range: typeof import("@zwa73/js-utils").JsFunc.range, preset: typeof import("@zwa73/js-utils").JsFunc.preset, assignOption: typeof import("@zwa73/js-utils").JsFunc.assignOption;
3
3
  export declare const stylizePath: typeof UtilFT.stylizePath, posixizePath: typeof UtilFT.posixizePath, win32izePath: typeof UtilFT.win32izePath, currosizePath: typeof UtilFT.currosizePath;
4
4
  export declare const when: <const S extends import("@zwa73/js-utils").Keyable, T, R>(stat: import("@zwa73/js-utils").Literal<S>, f: (arg: Extract<T, import("@zwa73/js-utils").Matchable<S>>) => R) => (arg: T) => (false extends (symbol extends T ? S extends T & symbol ? false : true : string extends T ? S extends T & string ? false : true : number extends T ? S extends T & number ? false : true : true) ? T | R : import("@zwa73/js-utils").MatchableFlag<T> extends S ? Exclude<T, import("@zwa73/js-utils").Matchable<S>> | R : import("@zwa73/js-utils").MatchableFlag<T> extends Exclude<S, import("@zwa73/js-utils").MatchableFlag<T>> ? T : Exclude<T, import("@zwa73/js-utils").Matchable<S>> | R), map: typeof import("@zwa73/js-utils").JsFP.map, flow: typeof import("@zwa73/js-utils").JsFP.flow, pipe: typeof import("@zwa73/js-utils").JsFP.pipe, chain: <T, R>(f: (arg: Extract<T, import("@zwa73/js-utils").Matchable<typeof import("@zwa73/js-utils").Success>>) => R) => (arg: T) => false extends (symbol extends T ? typeof import("@zwa73/js-utils").Success extends infer T_1 ? T_1 extends typeof import("@zwa73/js-utils").Success ? T_1 extends T & symbol ? false : true : never : never : string extends T ? typeof import("@zwa73/js-utils").Success extends infer T_2 ? T_2 extends typeof import("@zwa73/js-utils").Success ? T_2 extends T & string ? false : true : never : never : number extends T ? typeof import("@zwa73/js-utils").Success extends infer T_3 ? T_3 extends typeof import("@zwa73/js-utils").Success ? T_3 extends T & number ? false : true : never : never : true) ? T | R : import("@zwa73/js-utils").MatchableFlag<T> extends typeof import("@zwa73/js-utils").Success ? R | Exclude<T, import("@zwa73/js-utils").Matchable<typeof import("@zwa73/js-utils").Success>> : import("@zwa73/js-utils").MatchableFlag<T> extends Exclude<typeof import("@zwa73/js-utils").Success, import("@zwa73/js-utils").MatchableFlag<T>> ? T : R | Exclude<T, import("@zwa73/js-utils").Matchable<typeof import("@zwa73/js-utils").Success>>, alt: <T, R>(f: (arg: Extract<T, import("@zwa73/js-utils").Matchable<typeof import("@zwa73/js-utils").Failed>>) => R) => (arg: T) => false extends (symbol extends T ? typeof import("@zwa73/js-utils").Failed extends infer T_1 ? T_1 extends typeof import("@zwa73/js-utils").Failed ? T_1 extends T & symbol ? false : true : never : never : string extends T ? typeof import("@zwa73/js-utils").Failed extends infer T_2 ? T_2 extends typeof import("@zwa73/js-utils").Failed ? T_2 extends T & string ? false : true : never : never : number extends T ? typeof import("@zwa73/js-utils").Failed extends infer T_3 ? T_3 extends typeof import("@zwa73/js-utils").Failed ? T_3 extends T & number ? false : true : never : never : true) ? T | R : import("@zwa73/js-utils").MatchableFlag<T> extends typeof import("@zwa73/js-utils").Failed ? R | Exclude<T, import("@zwa73/js-utils").Matchable<typeof import("@zwa73/js-utils").Failed>> : import("@zwa73/js-utils").MatchableFlag<T> extends Exclude<typeof import("@zwa73/js-utils").Failed, import("@zwa73/js-utils").MatchableFlag<T>> ? T : R | Exclude<T, import("@zwa73/js-utils").Matchable<typeof import("@zwa73/js-utils").Failed>>, tap: typeof import("@zwa73/js-utils").JsFP.tap, curry: typeof import("@zwa73/js-utils").JsFP.curry;
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.curry = exports.tap = exports.alt = exports.chain = exports.pipe = exports.flow = exports.map = exports.when = exports.currosizePath = exports.win32izePath = exports.posixizePath = exports.stylizePath = exports.assignOption = exports.preset = exports.range = exports.structEqual = exports.s2l = exports.l2s = exports.ivk = exports.lazyFunction = exports.memoize = exports.eitherize = exports.throwError = exports.dedent = exports.mapEntries = exports.getTime = exports.stringifyJToken = exports.sleep = exports.deepClone = exports.assertType = exports.checkLiteral = exports.checkType = exports.isSafeNumber = exports.match = exports.failed = exports.success = exports.extractOutcome = exports.outcome = void 0;
3
+ exports.curry = exports.tap = exports.alt = exports.chain = exports.pipe = exports.flow = exports.map = exports.when = exports.currosizePath = exports.win32izePath = exports.posixizePath = exports.stylizePath = exports.assignOption = exports.preset = exports.range = exports.structEqual = exports.s2l = exports.l2s = exports.ivk = exports.lazyFunction = exports.memoize = exports.eitherize = exports.throwError = exports.dedent = exports.mapEntries = exports.getTime = exports.stringifyJToken = exports.sleep = exports.deepClone = exports.assertType = exports.constrainLiteral = exports.constrainType = exports.isSafeNumber = exports.match = exports.failed = exports.success = exports.extractOutcome = exports.outcome = void 0;
4
4
  const UtilFileTools_1 = require("./UtilFileTools");
5
5
  const UtilFP_1 = require("./UtilFP");
6
6
  const UtilFunctions_1 = require("./UtilFunctions");
7
- exports.outcome = UtilFunctions_1.UtilFunc.outcome, exports.extractOutcome = UtilFunctions_1.UtilFunc.extractOutcome, exports.success = UtilFunctions_1.UtilFunc.success, exports.failed = UtilFunctions_1.UtilFunc.failed, exports.match = UtilFunctions_1.UtilFunc.match, exports.isSafeNumber = UtilFunctions_1.UtilFunc.isSafeNumber, exports.checkType = UtilFunctions_1.UtilFunc.checkType, exports.checkLiteral = UtilFunctions_1.UtilFunc.checkLiteral, exports.assertType = UtilFunctions_1.UtilFunc.assertType, exports.deepClone = UtilFunctions_1.UtilFunc.deepClone, exports.sleep = UtilFunctions_1.UtilFunc.sleep, exports.stringifyJToken = UtilFunctions_1.UtilFunc.stringifyJToken, exports.getTime = UtilFunctions_1.UtilFunc.getTime, exports.mapEntries = UtilFunctions_1.UtilFunc.mapEntries, exports.dedent = UtilFunctions_1.UtilFunc.dedent, exports.throwError = UtilFunctions_1.UtilFunc.throwError, exports.eitherize = UtilFunctions_1.UtilFunc.eitherize, exports.memoize = UtilFunctions_1.UtilFunc.memoize, exports.lazyFunction = UtilFunctions_1.UtilFunc.lazyFunction, exports.ivk = UtilFunctions_1.UtilFunc.ivk, exports.l2s = UtilFunctions_1.UtilFunc.l2s, exports.s2l = UtilFunctions_1.UtilFunc.s2l, exports.structEqual = UtilFunctions_1.UtilFunc.structEqual, exports.range = UtilFunctions_1.UtilFunc.range, exports.preset = UtilFunctions_1.UtilFunc.preset, exports.assignOption = UtilFunctions_1.UtilFunc.assignOption;
7
+ exports.outcome = UtilFunctions_1.UtilFunc.outcome, exports.extractOutcome = UtilFunctions_1.UtilFunc.extractOutcome, exports.success = UtilFunctions_1.UtilFunc.success, exports.failed = UtilFunctions_1.UtilFunc.failed, exports.match = UtilFunctions_1.UtilFunc.match, exports.isSafeNumber = UtilFunctions_1.UtilFunc.isSafeNumber, exports.constrainType = UtilFunctions_1.UtilFunc.constrainType, exports.constrainLiteral = UtilFunctions_1.UtilFunc.constrainLiteral, exports.assertType = UtilFunctions_1.UtilFunc.assertType, exports.deepClone = UtilFunctions_1.UtilFunc.deepClone, exports.sleep = UtilFunctions_1.UtilFunc.sleep, exports.stringifyJToken = UtilFunctions_1.UtilFunc.stringifyJToken, exports.getTime = UtilFunctions_1.UtilFunc.getTime, exports.mapEntries = UtilFunctions_1.UtilFunc.mapEntries, exports.dedent = UtilFunctions_1.UtilFunc.dedent, exports.throwError = UtilFunctions_1.UtilFunc.throwError, exports.eitherize = UtilFunctions_1.UtilFunc.eitherize, exports.memoize = UtilFunctions_1.UtilFunc.memoize, exports.lazyFunction = UtilFunctions_1.UtilFunc.lazyFunction, exports.ivk = UtilFunctions_1.UtilFunc.ivk, exports.l2s = UtilFunctions_1.UtilFunc.l2s, exports.s2l = UtilFunctions_1.UtilFunc.s2l, exports.structEqual = UtilFunctions_1.UtilFunc.structEqual, exports.range = UtilFunctions_1.UtilFunc.range, exports.preset = UtilFunctions_1.UtilFunc.preset, exports.assignOption = UtilFunctions_1.UtilFunc.assignOption;
8
8
  exports.stylizePath = UtilFileTools_1.UtilFT.stylizePath, exports.posixizePath = UtilFileTools_1.UtilFT.posixizePath, exports.win32izePath = UtilFileTools_1.UtilFT.win32izePath, exports.currosizePath = UtilFileTools_1.UtilFT.currosizePath;
9
9
  exports.when = UtilFP_1.UtilFP.when, exports.map = UtilFP_1.UtilFP.map, exports.flow = UtilFP_1.UtilFP.flow, exports.pipe = UtilFP_1.UtilFP.pipe, exports.chain = UtilFP_1.UtilFP.chain, exports.alt = UtilFP_1.UtilFP.alt, exports.tap = UtilFP_1.UtilFP.tap, exports.curry = UtilFP_1.UtilFP.curry;
10
10
  if (false) {
@@ -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" | "checkType" | "checkLiteral" | "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 {};
@@ -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 FormData from "form-data";
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: http.IncomingHttpHeaders;
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
- /**请求的log等级 默认http 不影响警告 */
16
+ /** 请求的log等级 默认http 不影响警告 */
18
17
  logLevel?: LogLevel;
19
- /**请求协议 */
18
+ /** 请求协议 */
20
19
  protocol: 'http:' | 'https:';
21
- /**超时时间/毫秒 最小为10_000 默认无限 */
20
+ /** 超时时间/毫秒 最小为10_000 默认无限 传入signal时无效 */
22
21
  timeout?: number;
23
- /**请求域名 */
22
+ /** 请求域名 */
24
23
  hostname: string;
25
- /**请求路径 */
24
+ /** 请求路径 */
26
25
  path?: string;
27
- /**请求方式 post */
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
- responseEncode?: BufferEncoding;
40
- } & http.RequestOptions;
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
- /**请求处理函数 需调用req.end() */
44
- export type RequestProcFn = (req: http.ClientRequest) => MPromise<void>;
45
- /**结果处理函数 */
46
- export type RequestParseFn<D, R> = (result: RequestResult<D> | undefined, opt: RequestOption) => MPromise<R>;
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 AcceptProcCtor<D, R, T extends {}> = AcceptProcData<D, R> | ((arg: T) => MPromise<AcceptProcData<D, R>>);
56
- type AcceptProcData<D, R> = {
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
- proc: RequestProcFn;
57
+ body?: BodyInit;
58
+ headers?: Record<string, string>;
65
59
  };
66
60
  declare const SendNoneProc: SendProcCtor<{}>;
67
- declare const AcceptStringProc: AcceptProcCtor<string, RequestResult<string> | undefined, {}>;
68
- declare const AcceptNoneProc: AcceptProcCtor<undefined, RequestResult<undefined> | undefined, {}>;
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
- /**send处理的参数 */
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
- /**accept处理的结果 */
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, 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<string, RequestResult<string> | undefined, {}>>;
87
- /**设为http请求 */
76
+ }, SendProcCtor<{}>, AcceptProcCtor<RequestResult<string> | undefined, {}>>;
88
77
  static http(): UtilHttp<{
89
78
  readonly protocol: "http:";
90
- }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<string> | undefined, {}>>;
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<string, RequestResult<string> | undefined, {}>>;
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<HAD extends http.OutgoingHttpHeaders>(headers: HAD): UtilHttp<D & {
114
- headers: HAD;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
126
+ }) => MPromise<SendProcData>, AcceptProcData<RequestResult<JToken> | undefined>>;
140
127
  /**无查询参数获取json的get预设 */
141
128
  getJson(): UtilHttp<D & {
142
129
  method: "GET";
143
- }, SendProcCtor<{}>, AcceptProcData<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
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<string, RequestResult<JToken> | undefined>>;
207
- acceptJson(): UtilHttp<D, S, AcceptProcData<string, RequestResult<JToken> | undefined>>;
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<AD, AR, AT extends {}>(proc: AcceptProcCtor<AD, AR, AT>): UtilHttp<D, S, typeof proc>;
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
- /**form-data包提供的FormData表单数据 */
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: Omit<AcceptProcData<T, unknown>, 'parse'>): Promise<RequestResult<T> | undefined>;
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
- init: () => '',
26
- reduce: (acc, dat) => acc + dat,
27
- parse: result => {
28
- if (result == undefined) {
29
- UtilLogger_1.SLogger.warn(`accept json 接收反馈错误: 响应结果无效`);
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
- init: () => undefined,
37
- parse: result => {
38
- if (result == undefined) {
39
- UtilLogger_1.SLogger.warn(`accept none 接收反馈错误: 响应结果无效`);
40
- return undefined;
41
- }
42
- return result;
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
- init: () => '',
158
- reduce: (acc, curr) => acc + curr,
159
- parse: (result, opt) => {
160
- if (result == undefined) {
161
- UtilLogger_1.SLogger.warn(`accept json 接收反馈错误: 响应结果无效`);
162
- return undefined;
163
- }
164
- const { data, ...rest } = result;
165
- if (data.trim() == "") {
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(data.trim());
171
- UtilLogger_1.SLogger.log(opt.logLevel ?? 'none', `accept json 接受信息 data:`, UtilFunctions_1.UtilFunc.stringifyJToken(obj, { compress: true, space: 2 }), `result:`, UtilFunctions_1.UtilFunc.stringifyJToken(rest, { 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 接收反馈错误:`, err, UtilFunctions_1.UtilFunc.stringifyJToken(result, { compress: true, space: 2 }));
176
- return { ...result, raw: data, data: null };
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
- init: res => {
194
- const fileStream = fs_1.default.createWriteStream(arg.acceptFilepath);
195
- const fileWritePromise = new Promise((resolve) => {
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
- const success = await result.data.promise;
213
- if (!success)
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
- return { ...result, filepath: arg.acceptFilepath };
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
- const { method } = opt;
234
- const isPost = (method == "POST");
235
- const data = JSON.stringify(arg.json);
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 snedProc = (opt, arg) => {
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
- proc: async (req) => {
275
- if (isPost) {
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 = snedProc;
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
- proc: (req) => {
300
- if (isPost)
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.append(filename, fs_1.default.createReadStream(filepath));
319
- opt.headers = {
320
- ...formData.getHeaders(),
321
- ...opt.headers
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
- ? await this._send(fullopt, arg)
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 parse(res, fullopt);
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 { reduce: reqReduce, init: reqInit } = acceptProc;
380
- const { proc: reqProc } = sendProc;
381
- //拆分扩展部分
382
- const { protocol, logLevel, timeout, ...baseReqOpt } = UtilFunctions_1.UtilFunc.assignOption(RequestDefOption, option);
383
- const plusTimeout = timeout + 1000;
384
- const hasTimeLimit = timeout >= 10_000;
385
- const flagName = `UtilHttp.request ${protocol}${baseReqOpt.method} ${UtilFunctions_1.UtilFunc.genUUID()}`;
386
- const reduceQueue = new js_utils_1.PromiseQueue();
387
- let dataPromise = null;
388
- return new Promise(async (resolve, rejecte) => {
389
- const finallyTimeout = hasTimeLimit
390
- ? setTimeout(() => {
391
- UtilLogger_1.SLogger.warn(`${flagName} finallyTimeout 超时 ${timeout} ms, 终止请求`);
392
- req.destroy();
393
- resolve(undefined);
394
- }, plusTimeout)
395
- : undefined;
396
- const finallyResolve = (t) => {
397
- clearTimeout(finallyTimeout);
398
- resolve(t);
399
- };
400
- const resFunc = async (res) => {
401
- try {
402
- //请求超时
403
- if (hasTimeLimit) {
404
- res.setTimeout(timeout, () => {
405
- UtilLogger_1.SLogger.warn(`${flagName} http.response 触发 ${timeout} ms 超时, 继续挂起等待`);
406
- });
407
- }
408
- let mergedata;
409
- try {
410
- mergedata = await reqInit(res);
411
- }
412
- catch (err) {
413
- UtilLogger_1.SLogger.error(`${flagName} init函数错误:`, err);
414
- finallyResolve(undefined);
415
- return;
416
- }
417
- res.setEncoding(option.responseEncode ?? 'utf8');
418
- if (reqReduce) {
419
- res.on('data', chunk => {
420
- dataPromise = reduceQueue
421
- .enqueue(async () => {
422
- try {
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
- req.on('error', err => {
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
+ })();
@@ -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";
@@ -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): SLogger;
15
+ static getLogger(name?: string): ILoggerFull;
15
16
  /**创建Logger
16
- * @param opt - 创建参数
17
- * @returns 创建完成的logger
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
- }): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
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[]): SLogger;
140
+ static silly(...messages: any[]): ILoggerFull;
140
141
  /**让名称为default的logger 记录当前时间戳并存入表
141
142
  * @param flag - 记录的命名
142
143
  * @returns 记录的时间
143
144
  */
144
- static time(flag: string): HRTimeLog;
145
+ static time(flag: string): void;
145
146
  /**让名称为default的logger 根据之前记录的时间戳计算经过的时间 并输出log
146
147
  * @param flag - 记录的命名
147
148
  * @param level - log等级
@@ -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 创建完成的logger
63
+ * @param opt - ILogger 实例或创建参数
64
+ * @returns ILogger
64
65
  */
65
66
  static createLogger(opt) {
66
- const { name = "default", consoleLevel = "info", outFloder, fileLevel = "info" } = opt ?? {};
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
- old._logger.transports.forEach(tp => {
116
- if (tp.close != null)
117
- tp.close();
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.293",
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": [