@anjianshi/utils 3.1.2 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,5 +5,5 @@ export declare const withTransaction: (client: any) => import("@prisma/client/ex
5
5
  }>>;
6
6
  export type GetPrismaClientInTransaction<PrismaClient> = Omit<PrismaClient, ITXClientDenyList>;
7
7
  export type WithTransactionMethod = typeof $withTransaction;
8
- declare function $withTransaction<That extends object, R extends Result<unknown, unknown>>(this: That, callback: (dbInTransaction: GetPrismaClientInTransaction<That>) => Promise<R>): Promise<Failed<any> | R>;
8
+ declare function $withTransaction<That extends object, R extends Result>(this: That, callback: (dbInTransaction: GetPrismaClientInTransaction<That>) => Promise<R>): Promise<R | Failed<unknown, any>>;
9
9
  export {};
@@ -26,8 +26,10 @@ class FailedInTransaction extends Error {
26
26
  this.failed = failed;
27
27
  }
28
28
  }
29
- // 注意:此函数的返回值为 `R | Failed<any>`,例如实际可能为 `Result<xxx, xxx> | Failed<any>`,这是有意为之的,`Failed<any>` 并不多余。
30
- // 因为有时 callback() 只会返回 success 结果,此时 R=Success<xxx>,但是 $withTransaction 整体的返回值仍有可能有 Failed<any>,所以不能用 R 作为整体返回值。
29
+ // 注意:此函数的返回值为 `R | Failed<unknown, any>`,例如实际可能为 `Result<xxx, xxx> | Failed<unknown, any>`,
30
+ // 这是有意为之的,`Failed<unknown, any>` 并不多余。
31
+ // 因为有时 callback() 只会返回 success 结果,此时 R=Success<xxx>,
32
+ // 但是 $withTransaction 整体的返回值仍有可能有 Failed<unknown, any>,所以不能用 R 作为整体返回值。
31
33
  async function $withTransaction(callback) {
32
34
  const executeCallback = async (dbInTransaction) => {
33
35
  const result = await callback(dbInTransaction);
package/lang/result.d.ts CHANGED
@@ -16,34 +16,37 @@ export interface Success<T = void> {
16
16
  success: true;
17
17
  data: T;
18
18
  }
19
- export interface Failed<T = unknown> {
19
+ export interface Failed<CodeT = unknown, DataT = unknown> {
20
20
  success: false;
21
21
  message: string;
22
- code?: string | number;
23
- data: T;
22
+ code: CodeT;
23
+ data: DataT;
24
24
  }
25
- export type Result<T = void, FailedT = unknown> = Success<T> | Failed<FailedT>;
25
+ export type Result<DataT = unknown, FailedT extends Failed = Failed> = Success<DataT> | FailedT;
26
+ export type SuccessDataTypeOfResult<ResultT extends Result> = ResultT extends Success<infer DataT> ? DataT : never;
27
+ export type FailedTypeOfResult<ResultT extends Result> = ResultT extends Failed ? ResultT : never;
26
28
  /** 生成 Success 数据 */
27
29
  declare function success(): Success;
28
30
  declare function success<T>(data: T): Success<T>;
29
31
  export { success };
30
32
  /** 生成 Failed 数据 */
31
- declare function failed(message: string, code?: string | number): Failed;
32
- declare function failed<T>(message: string, code: string | number | undefined, data: T): Failed<T>;
33
+ declare function failed(message: string): Failed;
34
+ declare function failed<CodeT>(message: string, code: CodeT): Failed<CodeT>;
35
+ declare function failed<CodeT, DataT>(message: string, code: CodeT, data: DataT): Failed<CodeT, DataT>;
33
36
  export { failed };
34
37
  /**
35
38
  * 若传入值为 Success,格式化其 data;否则原样返回错误。
36
39
  *
37
40
  */
38
- declare function formatSuccess<T1, T2, FT = void>(value: Result<T1, FT>, formatter: (value: T1) => T2): Result<T2, FT>;
39
- declare function formatSuccess<T1, T2, FT = void>(value: Promise<Result<T1, FT>>, formatter: (value: T1) => T2): Promise<Result<T2, FT>>;
41
+ declare function formatSuccess<FormattedDataT, ResultT extends Result>(result: ResultT, formatter: (value: SuccessDataTypeOfResult<ResultT>) => FormattedDataT): Result<FormattedDataT, FailedTypeOfResult<ResultT>>;
42
+ declare function formatSuccess<FormattedDataT, ResultT extends Result>(result: Promise<ResultT>, formatter: (value: SuccessDataTypeOfResult<ResultT>) => FormattedDataT): Promise<Result<FormattedDataT, FailedTypeOfResult<ResultT>>>;
40
43
  export { formatSuccess };
41
44
  /**
42
45
  * 若传入值为 Failed,格式化其内容;否则原样返回。
43
46
  * 支持传入会返回 Result 的 Promise。
44
47
  */
45
- declare function formatFailed<T, FT>(value: Result<T>, formatter: (result: Failed) => Failed<FT>): Result<T, FT>;
46
- declare function formatFailed<T, FT>(value: Promise<Result<T>>, formatter: (result: Failed) => Failed<FT>): Promise<Result<T, FT>>;
48
+ declare function formatFailed<ResultT extends Result, FormattedFailedT extends Failed>(result: ResultT, formatter: (result: FailedTypeOfResult<ResultT>) => FormattedFailedT): Result<SuccessDataTypeOfResult<ResultT>, FormattedFailedT>;
49
+ declare function formatFailed<ResultT extends Result, FormattedFailedT extends Failed>(result: Promise<ResultT>, formatter: (result: FailedTypeOfResult<ResultT>) => FormattedFailedT): Promise<Result<SuccessDataTypeOfResult<ResultT>, FormattedFailedT>>;
47
50
  export { formatFailed };
48
51
  /**
49
52
  * 把可能抛出异常的 Promise 转换为返回 Result 的 Promise。
@@ -51,4 +54,4 @@ export { formatFailed };
51
54
  *
52
55
  * 通过此函数可避免写一长串嵌套的 try catch 语句。
53
56
  */
54
- export declare function exceptionToFailed<T>(promise: Promise<T>): Promise<Result<T>>;
57
+ export declare function exceptionToFailed<T>(promise: Promise<T>): Promise<Result<T, Failed<undefined>>>;
package/lang/result.js CHANGED
@@ -16,19 +16,21 @@ function success(data) {
16
16
  }
17
17
  export { success };
18
18
  function failed(message, code, data) {
19
- return { success: false, message, code, data: data };
19
+ return { success: false, message, code: code, data: data };
20
20
  }
21
21
  export { failed };
22
- function formatSuccess(value, formatter) {
23
- if ('then' in value)
24
- return value.then(finalValue => formatSuccess(finalValue, formatter));
25
- return value.success ? success(formatter(value.data)) : value;
22
+ function formatSuccess(result, formatter) {
23
+ if ('then' in result)
24
+ return result.then(finalValue => formatSuccess(finalValue, formatter));
25
+ return result.success
26
+ ? success(formatter(result.data))
27
+ : result;
26
28
  }
27
29
  export { formatSuccess };
28
- function formatFailed(value, formatter) {
29
- if ('then' in value)
30
- return value.then(finalValue => formatFailed(finalValue, formatter));
31
- return value.success ? value : formatter(value);
30
+ function formatFailed(result, formatter) {
31
+ if ('then' in result)
32
+ return result.then(finalResult => formatFailed(finalResult, formatter));
33
+ return result.success ? result : formatter(result);
32
34
  }
33
35
  export { formatFailed };
34
36
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anjianshi/utils",
3
- "version": "3.1.2",
3
+ "version": "3.2.0",
4
4
  "description": "Common JavaScript Utils",
5
5
  "homepage": "https://github.com/anjianshi/js-packages/utils",
6
6
  "bugs": {
@@ -31,10 +31,10 @@
31
31
  "redis": "^5.5.6",
32
32
  "typescript": "^5.8.3",
33
33
  "vconsole": "^3.15.1",
34
+ "@anjianshi/presets-eslint-base": "6.0.0",
34
35
  "@anjianshi/presets-eslint-node": "6.0.0",
35
- "@anjianshi/presets-eslint-typescript": "6.0.0",
36
36
  "@anjianshi/presets-eslint-react": "6.0.0",
37
- "@anjianshi/presets-eslint-base": "6.0.0",
37
+ "@anjianshi/presets-eslint-typescript": "6.0.0",
38
38
  "@anjianshi/presets-typescript": "3.2.5",
39
39
  "@anjianshi/presets-prettier": "3.0.5"
40
40
  },
@@ -1,9 +1,9 @@
1
1
  import { type Result, type Failed } from '../lang/result.js';
2
2
  import { type Logger } from '../logging/index.js';
3
- import { type RequestError } from './error.js';
3
+ import { type RequestFailed } from './error.js';
4
4
  import type { Options, PredefinedOptions, FormattedOptions } from './options.js';
5
5
  /** 此基类不可直接使用,因其未对错误格式进行具体约定 */
6
- export declare abstract class BaseRequestClient<FailedT> {
6
+ export declare abstract class BaseRequestClient<FailedT extends Failed> {
7
7
  readonly logger: Logger;
8
8
  readonly prefefinedOptions: PredefinedOptions;
9
9
  constructor(options?: PredefinedOptions & {
@@ -25,11 +25,11 @@ export declare abstract class BaseRequestClient<FailedT> {
25
25
  * - 其他情况,返回纯文本结果
26
26
  */
27
27
  protected parseResponse(options: FormattedOptions, response: Response): Promise<Result<unknown, FailedT>>;
28
- protected handleError(error: RequestError): Failed<FailedT>;
28
+ protected handleError(result: RequestFailed): FailedT;
29
29
  /** 生成符合 FailedT 约定的失败结果 */
30
- protected abstract makeFailedResult(error: RequestError): Failed<FailedT>;
30
+ protected abstract makeFailedResult(result: RequestFailed): FailedT;
31
31
  }
32
32
  /** 默认的 RequestClient 实现。出现错误时,会把错误对象原样放入错误信息中。 */
33
- export declare class RequestClient extends BaseRequestClient<RequestError> {
34
- protected makeFailedResult(error: RequestError): Failed<RequestError>;
33
+ export declare class RequestClient extends BaseRequestClient<RequestFailed> {
34
+ protected makeFailedResult(result: RequestFailed): RequestFailed;
35
35
  }
package/request/client.js CHANGED
@@ -6,7 +6,6 @@ import pick from 'lodash/pick.js';
6
6
  import { success, failed, formatFailed, exceptionToFailed, } from '../lang/result.js';
7
7
  import { getLogger } from '../logging/index.js';
8
8
  import { combineUrl } from '../url.js';
9
- import { SendRequestFailed, RequestAborted, RequestTimedOut, NonSuccessStatus, ParseResponseBodyFailed, } from './error.js';
10
9
  /** 此基类不可直接使用,因其未对错误格式进行具体约定 */
11
10
  export class BaseRequestClient {
12
11
  logger;
@@ -41,21 +40,26 @@ export class BaseRequestClient {
41
40
  // 失败情形“手动取消”
42
41
  if (manualSignal && manualSignal.aborted && manualSignal.reason === error) {
43
42
  const reason = error instanceof DOMException && error.name === 'AbortError' ? null : error;
44
- return this.handleError(new RequestAborted(reason, options));
43
+ return this.handleError(failed('Request Aborted', 'RequestAborted', { options, reason }));
45
44
  }
46
45
  // 失败情形“请求超时”
47
46
  if (error instanceof DOMException && error.name === 'TimeoutError') {
48
- return this.handleError(new RequestTimedOut(options));
47
+ return this.handleError(failed('Request Timeouted Out', 'RequestTimedOut', { options }));
49
48
  }
50
49
  // 失败情形“请求发起失败”
51
- return this.handleError(new SendRequestFailed(error, options));
50
+ return this.handleError(failed('Request Timeouted Out', 'RequestTimedOut', { options, originalError: error }));
52
51
  }
53
52
  // 失败情形“失败状态码”
54
53
  if (!response.status.toString().startsWith('2')) {
55
54
  // 此时服务端仍可能输出一些内容,试着解析出来
56
55
  const responseDataRes = await this.parseResponse(options, response);
57
56
  const responseData = responseDataRes.success ? responseDataRes.data : undefined;
58
- return this.handleError(new NonSuccessStatus(response, responseData, options));
57
+ return this.handleError(failed('Non-Success Status', 'NonSuccessStatus', {
58
+ options,
59
+ status: response.status,
60
+ response,
61
+ responseData,
62
+ }));
59
63
  }
60
64
  // 解析响应内容
61
65
  const result = await this.parseResponse(options, response);
@@ -118,11 +122,21 @@ export class BaseRequestClient {
118
122
  const contentType = (response.headers.get('Content-Type') ?? '').toLowerCase().trim();
119
123
  if (options.binary) {
120
124
  const blobResult = await exceptionToFailed(response.blob());
121
- return formatFailed(blobResult, result => this.handleError(new ParseResponseBodyFailed(result.data, response, options, 'Parse Blob Body Failed')));
125
+ return formatFailed(blobResult, result => this.handleError(failed('Parse Blob Body Failed', 'ParseResponseBodyFailed', {
126
+ options,
127
+ status: response.status,
128
+ originalError: result.data,
129
+ response,
130
+ })));
122
131
  }
123
132
  const textResult = await exceptionToFailed(response.text());
124
133
  if (contentType.startsWith('text/') || !textResult.success) {
125
- return formatFailed(textResult, result => this.handleError(new ParseResponseBodyFailed(result.data, response, options, 'Parse Text Body Failed')));
134
+ return formatFailed(textResult, result => this.handleError(failed('Parse Text Body Failed', 'ParseResponseBodyFailed', {
135
+ options,
136
+ status: response.status,
137
+ originalError: result.data,
138
+ response,
139
+ })));
126
140
  }
127
141
  let jsonParseError;
128
142
  try {
@@ -132,23 +146,28 @@ export class BaseRequestClient {
132
146
  jsonParseError = error;
133
147
  }
134
148
  if (contentType.startsWith('application/json')) {
135
- return this.handleError(new ParseResponseBodyFailed(jsonParseError, response, options, 'Parse JSON Body Failed'));
149
+ return this.handleError(failed('Parse JSON Body Failed', 'ParseResponseBodyFailed', {
150
+ options,
151
+ status: response.status,
152
+ originalError: jsonParseError,
153
+ response,
154
+ }));
136
155
  }
137
156
  return textResult;
138
157
  }
139
- handleError(error) {
140
- const info = pick(error.options, ['url', 'method']);
158
+ handleError(result) {
159
+ const info = pick(result.data.options, ['url', 'method']);
141
160
  for (const key of ['originalError', 'status', 'responseData']) {
142
- if (key in error)
143
- Object.assign(info, pick(error, [key]));
161
+ if (key in result.data)
162
+ Object.assign(info, pick(result.data, [key]));
144
163
  }
145
- this.logger.error(error.message, info);
146
- return this.makeFailedResult(error);
164
+ this.logger.error(result.code, info);
165
+ return this.makeFailedResult(result);
147
166
  }
148
167
  }
149
168
  /** 默认的 RequestClient 实现。出现错误时,会把错误对象原样放入错误信息中。 */
150
169
  export class RequestClient extends BaseRequestClient {
151
- makeFailedResult(error) {
152
- return failed(error.message, undefined, error);
170
+ makeFailedResult(result) {
171
+ return result;
153
172
  }
154
173
  }
@@ -6,37 +6,43 @@
6
6
  * 2. 请求本身成功,但相应内容表达了业务上的失败,例如登录接口返回密码错误。
7
7
  * 如有需要,可继承子类来处理这些失败情形。
8
8
  */
9
+ import { type Failed } from '../lang/result.js';
9
10
  import { type FormattedOptions } from './options.js';
10
- export declare class RequestError extends Error {
11
- readonly options: FormattedOptions;
12
- constructor(message: string, options: FormattedOptions);
11
+ export type RequestFailed = SendRequestFailed | RequestAborted | RequestTimedOut | NonSuccessStatus | ParseResponseBodyFailed;
12
+ export interface RequestFailedInfo {
13
+ options: FormattedOptions;
13
14
  }
14
15
  /** 手动取消 */
15
- export declare class RequestAborted extends RequestError {
16
+ export type RequestAborted = Failed<'RequestAborted', RequestAbortedInfo>;
17
+ export interface RequestAbortedInfo extends RequestFailedInfo {
16
18
  /** 取消原因,即调用 abortController.abort() 时传入的值,若未传值则为 null */
17
- readonly reason: unknown;
18
- constructor(reason: unknown, options: FormattedOptions);
19
+ reason: unknown;
19
20
  }
20
21
  /** 请求超时 */
21
- export declare class RequestTimedOut extends RequestError {
22
- constructor(options: FormattedOptions);
23
- }
22
+ export type RequestTimedOut = Failed<'RequestTimedOut', RequestFailedInfo>;
24
23
  /** 请求发起失败(如网络异常) */
25
- export declare class SendRequestFailed extends RequestError {
26
- readonly originalError: unknown;
27
- constructor(originalError: unknown, options: FormattedOptions);
24
+ export type SendRequestFailed = Failed<'SendRequestFailed', SendRequestFailedInfo>;
25
+ export interface SendRequestFailedInfo extends RequestFailedInfo {
26
+ /** 原始错误对象 */
27
+ originalError: unknown;
28
28
  }
29
29
  /** 失败状态码(服务端响应了代表失败的状态码,如 500) */
30
- export declare class NonSuccessStatus extends RequestError {
31
- readonly response: Response;
32
- readonly responseData: unknown;
33
- readonly status: number;
34
- constructor(response: Response, responseData: unknown, options: FormattedOptions);
30
+ export type NonSuccessStatus = Failed<'NonSuccessStatus', NonSuccessStatusInfo>;
31
+ export interface NonSuccessStatusInfo extends RequestFailedInfo {
32
+ /** HTTP Status */
33
+ status: number;
34
+ /** Response 对象 */
35
+ response: Response;
36
+ /** 尝试着从 response body 中解析出的数据 */
37
+ responseData: unknown;
35
38
  }
36
39
  /** 响应体解析失败 */
37
- export declare class ParseResponseBodyFailed extends RequestError {
38
- readonly originalError: unknown;
39
- readonly response: Response;
40
- readonly status: number;
41
- constructor(originalError: unknown, response: Response, options: FormattedOptions, message?: string);
40
+ export type ParseResponseBodyFailed = Failed<'ParseResponseBodyFailed', ParseResponseBodyFailedInfo>;
41
+ export interface ParseResponseBodyFailedInfo extends RequestFailedInfo {
42
+ /** HTTP Status */
43
+ status: number;
44
+ /** 原始错误对象 */
45
+ originalError: unknown;
46
+ /** Response 对象 */
47
+ response: Response;
42
48
  }
package/request/error.js CHANGED
@@ -1,54 +1 @@
1
- export class RequestError extends Error {
2
- options;
3
- constructor(message, options) {
4
- super(message);
5
- this.options = options;
6
- }
7
- }
8
- /** 手动取消 */
9
- export class RequestAborted extends RequestError {
10
- /** 取消原因,即调用 abortController.abort() 时传入的值,若未传值则为 null */
11
- reason;
12
- constructor(reason, options) {
13
- super('Request Aborted', options);
14
- this.reason = reason;
15
- }
16
- }
17
- /** 请求超时 */
18
- export class RequestTimedOut extends RequestError {
19
- constructor(options) {
20
- super('Request Timed Out', options);
21
- }
22
- }
23
- /** 请求发起失败(如网络异常) */
24
- export class SendRequestFailed extends RequestError {
25
- originalError;
26
- constructor(originalError, options) {
27
- super('Send Request Failed', options);
28
- this.originalError = originalError;
29
- }
30
- }
31
- /** 失败状态码(服务端响应了代表失败的状态码,如 500) */
32
- export class NonSuccessStatus extends RequestError {
33
- response;
34
- responseData;
35
- status;
36
- constructor(response, responseData, options) {
37
- super('Non-Success Status', options);
38
- this.response = response;
39
- this.responseData = responseData;
40
- this.status = response.status;
41
- }
42
- }
43
- /** 响应体解析失败 */
44
- export class ParseResponseBodyFailed extends RequestError {
45
- originalError;
46
- response;
47
- status;
48
- constructor(originalError, response, options, message) {
49
- super(message ?? 'Parse Response Body Failed', options);
50
- this.originalError = originalError;
51
- this.response = response;
52
- this.status = response.status;
53
- }
54
- }
1
+ export {};
@@ -1,4 +1,4 @@
1
1
  import { RequestClient } from './client.js';
2
2
  /** 提供一个即取即用的 RequestClient 实例及其函数版本 */
3
3
  export declare const client: RequestClient;
4
- export declare const request: <T>(inputUrl: string, inputOptions?: import("./options.js").Options) => Promise<import("../index.js").Result<T, import("./error.js").RequestError>>;
4
+ export declare const request: <T>(inputUrl: string, inputOptions?: import("./options.js").Options) => Promise<import("../index.js").Result<T, import("./error.js").RequestFailed>>;