npm package: @howuse/feedback
Description: Node.js/Electron SDK for user feedback and activation management
Latest version: 0.5.0

# @howuse/feedback

Node.js/Electron SDK for user feedback and activation management.

## 安装

```bash
npm install @howuse/feedback
```

或者使用本地路径安装：

```bash
npm install ./feedback-sdk
```

## 快速开始

### Node.js 示例

```typescript
import { initFeedbackClient } from '@howuse/feedback';

async function main() {
  // 初始化客户端
  const client = await initFeedbackClient({
    baseUrl: 'http://localhost:8080',
    softwareId: 1,
    version: '1.0.0',
  });

  // 检查是否可用
  if (!client.enabled) {
    console.warn('SDK is disabled, some features may not work');
    return;
  }

  // 提交反馈
  const feedbackResult = await client.feedback({
    content: 'This is a test feedback',
    email: 'user@example.com', // 可选
  });
  console.log('Feedback result:', feedbackResult);

  // 激活软件
  const activateResult = await client.activate({
    machineCode: 'your-machine-code',
    code: 'your-activation-code',
  });
  console.log('Activation result:', activateResult);

  // 检查激活状态
  const checkResult = await client.check({
    machineCode: 'your-machine-code',
  });
  if (checkResult.expired) {
    console.log('License expired:', checkResult.reason);
  } else {
    console.log('License valid until:', checkResult.expireAt);
  }
}

main().catch(console.error);
```

### Electron 主进程示例

在 Electron 的 `main.js` 或 `main.ts` 中：

```typescript
import { app, BrowserWindow } from 'electron';
import { initFeedbackClient } from '@howuse/feedback';

let feedbackClient: any;

async function initApp() {
  // 初始化 SDK
  feedbackClient = await initFeedbackClient({
    baseUrl: 'http://localhost:8080',
    softwareId: 1,
    version: app.getVersion(),
  });

  // 根据 enabled 状态决定是否显示反馈入口
  if (feedbackClient.enabled) {
    // 可以设置全局菜单或窗口中的反馈按钮
  }
}

app.whenReady().then(() => {
  initApp();
  createWindow();
});
```

## API 参考

### `initFeedbackClient(options: InitOptions): Promise<FeedbackClient>`

初始化 Feedback 客户端。

**参数：**

- `options.baseUrl` (string): 服务器基础 URL
- `options.softwareId` (number): 软件 ID
- `options.version` (string): 软件版本号
- `options.timeoutMs` (number, 可选): 请求超时时间（毫秒），默认 30000

**返回值：**

返回一个 `FeedbackClient` 实例。即使初始化失败，也不会抛出异常，而是返回 `enabled=false` 的客户端。

### `FeedbackClient`

#### 属性

- `enabled: boolean` - 指示 SDK 是否可用

#### 方法

##### `feedback(data: FeedbackPayload): Promise<FeedbackResult>`

提交用户反馈。

**参数：**

- `data.content` (string): 反馈内容（必填）
- `data.email` (string, 可选): 邮箱地址

**返回值：**

```typescript
{
  success: boolean;
  id?: number;
  error?: string;
}
```

##### `activate(data: ActivationRequest): Promise<ActivationResult>`

激活软件。

**参数：**

- `data.machineCode` (string): 机器码
- `data.code` (string): 激活码

**返回值：**

```typescript
{
  success: boolean;
  expireAt?: string;
  error?: string;
}
```

##### `check(data: ActivationCheckRequest): Promise<ActivationCheckResponse>`

检查激活状态。

**重要：** 如果调用失败（网络错误或服务器返回非 2xx），SDK 会直接返回 `expired: true`，而不是抛出异常。这确保了在无法联系服务端时，默认按"授权已到期"处理。

**参数：**

- `data.machineCode` (string): 机器码

**返回值：**

```typescript
{
  expired: boolean;
  activated?: boolean;
  expireAt?: string;
  reason?: string;
}
```

## 错误处理

SDK 采用"安全降级"策略：

1. **初始化失败**：不会抛出异常，而是返回 `enabled=false` 的客户端
2. **方法调用**：当 `enabled=false` 时，所有方法都会返回失败结果，而不是抛出异常
3. **激活检查失败**：`check` 方法在失败时会返回 `expired: true`，确保在无法联系服务端时默认按"授权已到期"处理

## 动态库支持

SDK 支持通过 Go 语言实现的动态库（native library）提供所有 HTTP 请求功能。如果动态库可用，SDK 会自动使用；否则会回退到纯 HTTP 实现。

### 动态库构建

动态库使用 Go 语言实现，源码位于项目根目录的 `native-sdk/` 目录。构建方法：

```bash
# macOS/Linux
cd native-sdk
./build.sh

# Windows
cd native-sdk
build.bat
```

构建完成后，动态库文件会输出到 `feedback-sdk/native/` 目录：

- macOS: `native/libhowuse_feedback.dylib`
- Windows: `native/howuse_feedback.dll`
- Linux: `native/libhowuse_feedback.so`

### 动态库优势

- **性能优化**：所有 HTTP 请求在 Go 层执行，性能更好
- **代码保护**：业务逻辑在编译后的动态库中，不易被逆向
- **统一实现**：HTTP 客户端逻辑统一在 Go 层管理

详细构建说明请参考 [native-sdk/README.md](./native-sdk/README.md)。

## 类型定义

所有类型都可以从包中导入：

```typescript
import type {
  InitOptions,
  FeedbackPayload,
  ActivationRequest,
  ActivationCheckRequest,
  // ... 其他类型
} from '@howuse/feedback';
```

## 许可证

MIT