# @buka/exception

标准异常类库，用于在应用中创建结构化的异常。

## 概述

`@buka/exception` 提供 `Exception` 基类，用于定义和抛出结构化异常，支持错误分类、模块标识、序列号及详细信息。

通常配合 `@buka/error-codes` 使用，以确保错误编码的一致性。

## 安装

```bash
pnpm add @buka/exception
```

## 基础用法

### 创建自定义异常

使用 `Exception` 基类创建项目特定的异常类：

```typescript
import { Exception } from "@buka/exception";

class ValidationException extends Exception {
  constructor(message: string, details = []) {
    super({
      message,
      category: 1, // 验证错误类别
      moduleId: 1,
      sequenceId: 1,
      details,
    });
  }
}

throw new ValidationException("Validation failed");
```

### 定义错误详情

通过实现添加异常详情

通过传递 `details` 提供错误的详细信息。可以是普通对象，也可以实现 `ExceptionDetail` 接口来规范化结构：

````typescript
import { type ExceptionDetail } from '@buka/exception'

// 方法 1：直接传递普通对象
throw new ValidationException('Validation failed', {
  type: 'field_validation',
  field: 'email',
  message: 'Invalid format'
})

// 方法 2：使用 ExceptionDetail 接口规范化
class FieldValidationDetail implements ExceptionDetail {
  readonly type = 'field_validation'

  constructor(
    public readonly field: string,
    public readonly message: string
  ) {}
}

throw new ValidationException(
  'Validation failed',
  new FieldValidationDetail('email', 'Invalid format')
)

// 多个详情
throw new ValidationException('Data validation failed', [
  new FieldValidationDetail('email', 'Invalid format'),
  new FieldValidationDetail('age', 'Must be positive')
]
## 异常捕获处理

```typescript
try {
  // 业务代码
} catch (error) {
  if (error instanceof ValidationException) {
    console.log(`Error: ${error.message}`)
    console.log(`Category: ${error.category}`)
    console.log(`Module: ${error.moduleId}`)
    console.log(`Details:`, error.details)
  }
}
````

## API 文档

### Exception

异常基类，继承自 `ts-custom-error` 的 `CustomError`。

#### 构造参数

```typescript
interface ExceptionOptions {
  message: string; // 错误消息
  category: number; // 错误类别
  moduleId: number; // 模块 ID
  sequenceId: number; // 序列 ID
  details?: ExceptionDetail | ExceptionDetail[]; // 可选的错误详情
}
```

#### 属性

- `message` - 错误消息
- `category` - 错误类别标识
- `moduleId` - 模块标识
- `sequenceId` - 序列号
- `details` - 错误详情数组（只读）

### ExceptionDetail

自定义错误详情的接口。

```typescript
interface ExceptionDetail {
  readonly type: string; // 详情类型
  [key: string]: unknown; // 允许附加属性
}
```

## 与 @buka/error-codes 配合使用

建议结合 `@buka/error-codes` 来管理错误码。`ErrorCode` 中包含了 `systemId`、`category`、`moduleId` 和 `sequenceId`，而 `Exception` 不包含 `systemId` 属性。这是因为 `systemId` 是应用系统级别的标识，应该由业务系统在统一的上下文中注入（如中间件、拦截器等），而非在异常定义时指定。这样设计使得二方包可以独立使用，而业务系统负责在异常处理层统一补充 `systemId` 信息。

定义业务系统的模块枚举和异常类：

```typescript
import { Exception, type ExceptionOptions } from "@buka/exception";
import { ErrorCode, ErrorCategory } from "@buka/error-codes";

// 定义模块枚举
enum ErrorModuleId {
  USER_SERVICE = 100,
  ORDER_SERVICE = 101,
  PAYMENT_SERVICE = 102,
}

// 定义异常类
class UserNotFoundException extends Exception {
  constructor(userId: string) {
    super({
      message: `User ${userId} not found`,
      category: ErrorCategory.BUSINESS,
      moduleId: ErrorModuleId.USER_SERVICE,
      sequenceId: 1,
      details: {
        type: "not_found",
        resource: "user",
        id: userId,
      },
    });
  }
}

class OrderValidationException extends Exception {
  constructor(message: string, details: object) {
    super({
      message,
      category: ErrorCategory.VALIDATION,
      moduleId: ErrorModuleId.ORDER_SERVICE,
      sequenceId: 1,
      details,
    });
  }
}
```
