diff --git a/packages/common/src/api/diagnostics.ts b/packages/common/src/api/diagnostics.ts index c50c051..72e1191 100644 --- a/packages/common/src/api/diagnostics.ts +++ b/packages/common/src/api/diagnostics.ts @@ -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 diff --git a/packages/common/src/api/useApi.ts b/packages/common/src/api/useApi.ts index d1a9e5b..9aec1ac 100644 --- a/packages/common/src/api/useApi.ts +++ b/packages/common/src/api/useApi.ts @@ -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 = = z.infer 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)) }, ) diff --git a/packages/common/src/api/useRequest.ts b/packages/common/src/api/useRequest.ts index c84f28a..e7a1316 100644 --- a/packages/common/src/api/useRequest.ts +++ b/packages/common/src/api/useRequest.ts @@ -21,13 +21,21 @@ export interface RequestOptions { // ─── 内部 ValidationError(对齐 @szyx-mobile/use-axios 的 ValidationError)──── -export class ValidationError 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 extends Error { + public readonly issues: z.ZodIssue[] + constructor( issues: z.ZodIssue[], public readonly response: AxiosResponse, ) { - super(issues) + super(issues[0]?.message ?? 'ValidationError') this.name = 'ValidationError' + this.issues = issues } } diff --git a/packages/update/android/xuqm-bundles.gradle b/packages/update/android/xuqm-bundles.gradle index c19363c..72686fe 100644 --- a/packages/update/android/xuqm-bundles.gradle +++ b/packages/update/android/xuqm-bundles.gradle @@ -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")