npm package: @howuse/feedback-node
Description: Pure Node.js SDK for user feedback and activation management (no Go/koffi dependencies)
Latest version: 0.5.0

# @howuse/feedback-node

纯 Node.js SDK for user feedback and activation management（无需 Go/koffi 依赖）.

## 安装

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

或者使用本地路径安装：

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

## 要求

- Node.js >= 18.0.0（内置 fetch API）

## 快速开始

### Node.js 示例

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

async function main() {
  // 初始化客户端
  const client = await initFeedbackClient({
    baseUrl: 'http://localhost:8080',
    softwareId: 1,
    version: '1.0.0',
    machineCodePath: './machine-codes', // 机器码存放目录
  });

  // 检查是否可用
  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({
    code: 'your-activation-code',
  });
  console.log('Activation result:', activateResult);

  // 检查激活状态（机器码会自动使用）
  const checkResult = await client.check();
  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-node';

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.machineCodePath` (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.code` (string): 激活码

**返回值：**

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

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

检查激活状态（机器码会自动从初始化时保存的位置读取）。

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

**参数：**

无需参数（机器码会自动使用）

**返回值：**

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

## 错误处理

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

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

## 实现说明

此 SDK 使用纯 Node.js 实现，无需 Go 语言或 koffi 依赖。所有功能（包括机器码生成、HTTP 请求等）都通过 Node.js 内置模块实现：

- **机器码生成**：基于系统用户名的 MD5 哈希 + UUID
- **HTTP 客户端**：使用 Node.js 18+ 内置的 `fetch` API
- **文件操作**：使用 Node.js `fs` 模块

### 机器码

机器码会自动生成并保存在指定的 `machineCodePath` 目录中。机器码格式为 32 位字符串，由以下两部分组成：
- 前 16 位：系统用户名的 MD5 哈希值前 16 位
- 后 16 位：UUID 的后 16 位

如果目录中已存在机器码文件（32 位文件名的文件），SDK 会自动使用现有的机器码，确保同一台机器上的机器码保持一致。

## 类型定义

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

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

## 许可证

MIT