errors.js
1.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* 结构化认证错误 —— 本包唯一对外错误类型(§3)。
*
* 所有失败一律抛 AuthError,禁止裸 Error / 静默吞错。`retryable` 给调用方决定
* 是否提示重试;`retryAfterMs` 仅 TOO_MANY_ATTEMPTS 携带。
*/
/**
* @typedef {'EMAIL_TAKEN'|'INVALID_CREDENTIALS'|'TOO_MANY_ATTEMPTS'|
* 'OAUTH_VERIFY_FAILED'|'REFRESH_REUSED'|'CODE_EXPIRED'|'CODE_INVALID'|
* 'TOKEN_INVALID'|'TOKEN_EXPIRED'|'USER_NOT_FOUND'|'UNSUPPORTED_PROVIDER'} AuthCode
*/
/** 默认可重试的错误码集合(瞬时/限流类)。 */
const RETRYABLE_CODES = new Set(['TOO_MANY_ATTEMPTS'])
export class AuthError extends Error {
/**
* @param {Object} info
* @param {AuthCode} info.code
* @param {boolean} [info.retryable]
* @param {number} [info.retryAfterMs]
* @param {unknown} [info.cause]
* @param {string} [info.message]
*/
constructor({ code, retryable, retryAfterMs, cause, message }) {
super(message ?? `auth failed: ${code}`)
this.name = 'AuthError'
/** @type {AuthCode} */
this.code = code
this.retryable = retryable ?? RETRYABLE_CODES.has(code)
if (retryAfterMs != null) this.retryAfterMs = retryAfterMs
if (cause != null) this.cause = cause
}
}
/**
* 把任意底层错误归一为 AuthError。已是 AuthError 的原样透传。
* @param {unknown} err
* @param {AuthCode} fallbackCode
* @returns {AuthError}
*/
export function asAuthError(err, fallbackCode) {
if (err instanceof AuthError) return err
return new AuthError({ code: fallbackCode, cause: err })
}