fix(common): ValidationError 改为继承 Error 修复 Hermes 校验崩溃
- Babel 转译子类 apply 调用原生 ZodError 在 Hermes 抛 TypeError,掩盖真实校验失败 - unexpected 分支补安全诊断日志(构造名+截断消息) - xuqm-bundles.gradle 将 file: 依赖的 src/metro 纳入任务输入
这个提交包含在:
父节点
507ce3d2ee
当前提交
d009c3b616
@ -64,6 +64,17 @@ export function createAxiosDiagnostic(error: AxiosError): SafeApiDiagnostic {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 非 axios 异常只允许记录构造名与截断消息。
|
||||
* 不接触 cause、stack、config 或任何可能持有业务数据的对象。
|
||||
*/
|
||||
export function createUnexpectedDiagnostic(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return `${error.name}: ${error.message.slice(0, 200)}`
|
||||
}
|
||||
return typeof error
|
||||
}
|
||||
|
||||
type ValidationCause = {
|
||||
issues: z.ZodIssue[]
|
||||
response: AxiosResponse<unknown>
|
||||
|
||||
@ -10,6 +10,7 @@ import { z } from 'zod'
|
||||
import {
|
||||
createAxiosDiagnostic,
|
||||
createResponseDiagnostic,
|
||||
createUnexpectedDiagnostic,
|
||||
createValidationDiagnostic,
|
||||
} from './diagnostics'
|
||||
import { RequestError } from './errors'
|
||||
@ -123,7 +124,13 @@ export const useApi = <S extends z.ZodTypeAny, T extends z.infer<S> = z.infer<S>
|
||||
return Promise.reject(new RequestError('网络请求失败', 'AxiosError', thrownError))
|
||||
}
|
||||
|
||||
console.error('[XuqmAPI] unexpected request failure')
|
||||
console.error(
|
||||
'[XuqmAPI] unexpected request failure',
|
||||
createUnexpectedDiagnostic(thrownError),
|
||||
)
|
||||
if (thrownError instanceof Error && thrownError.stack) {
|
||||
console.error('[XuqmAPI] unexpected request failure stack', thrownError.stack)
|
||||
}
|
||||
return Promise.reject(new RequestError('网络请求失败', 'OtherError', thrownError))
|
||||
},
|
||||
)
|
||||
|
||||
@ -21,13 +21,21 @@ export interface RequestOptions {
|
||||
|
||||
// ─── 内部 ValidationError(对齐 @szyx-mobile/use-axios 的 ValidationError)────
|
||||
|
||||
export class ValidationError<T = unknown, D = unknown> extends z.ZodError {
|
||||
// 不能 extends z.ZodError:zod v4 的 ZodError 是 $constructor 工厂函数,
|
||||
// 其自定义 Symbol.hasInstance 要求实例已初始化 _zod.traits。Babel 转译的子类
|
||||
// 在 super() 之前先执行 _classCallCheck(this, ValidationError),此时 _zod 尚不
|
||||
// 存在,instanceof 返回 false,直接抛 “Cannot call a class as a function”,
|
||||
// 把真实的校验失败掩盖成非预期错误。
|
||||
export class ValidationError<T = unknown, D = unknown> extends Error {
|
||||
public readonly issues: z.ZodIssue[]
|
||||
|
||||
constructor(
|
||||
issues: z.ZodIssue[],
|
||||
public readonly response: AxiosResponse<T, D>,
|
||||
) {
|
||||
super(issues)
|
||||
super(issues[0]?.message ?? 'ValidationError')
|
||||
this.name = 'ValidationError'
|
||||
this.issues = issues
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -142,9 +142,12 @@ def prepareXuqmBundles = tasks.register(
|
||||
include("*.mjs")
|
||||
})
|
||||
// registry 依赖由不可变版本号进入 baseline;file: 依赖在版本不变时也可能修改
|
||||
// 原生源码,必须同时成为 Gradle 输入和 native baseline 内容。
|
||||
// 源码,必须同时成为 Gradle 输入和 native baseline 内容。
|
||||
// JS/TS 源码决定 bundle 内容,android/ios 决定 native baseline,缺一不可。
|
||||
xuqmLocalDependencyDirectories.each { dependencyDirectory ->
|
||||
sourceFiles.from(project.fileTree(dependencyDirectory) {
|
||||
include("src/**")
|
||||
include("metro/**")
|
||||
include("android/**")
|
||||
include("ios/**")
|
||||
include("*.podspec")
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户