npm package: @seepine/hono-snowflake
Description: Hono middleware for generating Snowflake ID. Generate globally unique, distributed, and sortable IDs with customizable worker nodes.
Author: seepine
Latest version: 0.0.1

# hono-snowflake

[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![bundle][bundle-src]][bundle-href]
[![License][license-src]][license-href]

基于 [Hono](https://hono.dev/) 的雪花 ID 生成中间件。在每个请求中自动生成全局唯一的分布式 ID，适用于日志追踪、分布式系统中的唯一标识等场景。

## 主要特性

- **分布式唯一 ID 生成**  
  基于雪花算法（Snowflake Algorithm），确保生成的 ID 全局唯一且趋势递增。
- **开箱即用**  
  集成为 Hono 中间件，无需复杂配置，在请求处理流程中自动注入。
- **灵活的工作节点配置**  
  支持静态配置或异步动态设置工作节点 ID，适应各种部署场景。
- **可自定义位长**  
  支持自定义工作节点 ID 位长和序列号位长，平衡性能和唯一性需求。

## 安装

```bash
npm install @seepine/hono-snowflake
```

## 使用方法

### 1. 基本使用

```ts
import { Hono } from 'hono'
import { createSnowflakeMiddleware } from '@seepine/hono-snowflake'

const app = new Hono()
const { snowflakeMiddleware } = createSnowflakeMiddleware({
  workerId: 1, // 机器节点 ID
})
app.use(snowflakeMiddleware)

app.get('/test', c => {
  const id = c.var.snowflake.nextId()
  return c.json({ id })
})
```

### 2. 获取工作节点 ID

```ts
app.get('/worker-info', c => {
  const workerId = c.var.snowflake.getWorkerId()
  const id = c.var.snowflake.nextId()
  return c.json({ workerId, id })
})
```

### 3. 异步设置工作节点 ID

```ts
const getWorkerId = async () => {
  // 例如从配置服务或环境变量动态获取
  return Promise.resolve(2)
}

const { snowflakeMiddleware, snowflake } = createSnowflakeMiddleware({
  workerId: getWorkerId,
})
app.use(snowflakeMiddleware)
```

### 4. 全局访问（可选）

```ts
const { snowflakeMiddleware, snowflake } = createSnowflakeMiddleware({
  workerId: 1,
})
app.use(snowflakeMiddleware)

// 在全局作用域中保存，可在任何地方访问
globalThis.snowflake = snowflake

// 在任何地方获取 ID
const id = globalThis.snowflake.nextId()
```

## 配置选项

### `SnowflakeOpts`

| 选项                | 类型                              | 默认值                                               | 说明                                            |
| ------------------- | --------------------------------- | ---------------------------------------------------- | ----------------------------------------------- |
| `workerId`          | `number \| () => Promise<number>` | `process.env.SNOWFLAKE_WORKER_ID \|\| 1`             | 机器节点 ID，最大值为 `2^workerIdBitLength - 1` |
| `workerIdBitLength` | `number`                          | `process.env.SNOWFLAKE_WORKER_ID_BIT_LENGTH \|\| 10` | 工作节点 ID 位长，取值范围 [1, 15]              |
| `seqBitLength`      | `number`                          | `process.env.SNOWFLAKE_SEQ_BIT_LENGTH \|\| 10`       | 序列号位长，取值范围 [3, 21]                    |

**注意**：`seqBitLength + workerIdBitLength` 不能超过 22

## API

### `createSnowflakeMiddleware(opts?)`

创建雪花 ID 中间件。

**返回值**：

```ts
{
  snowflake: Snowflake,
  snowflakeMiddleware: Middleware
}
```

### `Snowflake` 类型

| 方法            | 返回值   | 说明                             |
| --------------- | -------- | -------------------------------- |
| `nextId()`      | `string` | 生成下一个雪花 ID（字符串形式）  |
| `nextBigId()`   | `bigint` | 生成下一个雪花 ID（BigInt 形式） |
| `getWorkerId()` | `number` | 获取当前工作节点 ID              |

## 示例

```ts
import { Hono } from 'hono'
import { createSnowflakeMiddleware } from '@seepine/hono-snowflake'

const app = new Hono()
const { snowflakeMiddleware } = createSnowflakeMiddleware({
  workerId: 1,
  workerIdBitLength: 10,
  seqBitLength: 12,
})

app.use(snowflakeMiddleware)

app.get('/id', c => {
  return c.text(`workerId:${c.var.snowflake.getWorkerId()},Id:${c.var.snowflake.nextId()}`)
})

app.listen(3000)
```

## 环境变量

如果不在初始化时指定配置，可通过环境变量进行配置：

```bash
# 工作节点 ID
SNOWFLAKE_WORKER_ID=1

# 工作节点 ID 位长
SNOWFLAKE_WORKER_ID_BIT_LENGTH=10

# 序列号位长
SNOWFLAKE_SEQ_BIT_LENGTH=10
```

## 注意事项

- 每个工作节点应该配置不同的 `workerId`，以确保全局唯一性
- `workerId` 不能超过 `2^workerIdBitLength - 1`
- 序列号位长和工作节点 ID 位长的组合决定了单位时间内的 ID 生成数量和节点支持数量
- 异步设置 `workerId` 时，在 Promise 完成前调用生成方法可能会失败，请确保在正确的时机调用

## 雪花算法说明

雪花 ID 是一个 64 位的分布式 ID，结构如下：

```
[1 符号位 | 41 时间戳位 | workerIdBitLength | seqBitLength]
```

- **符号位(1)**：始终为 0
- **时间戳位(41)**：毫秒级时间戳（可表示 69 年）
- **工作节点 ID**：支持多个节点生成不重复 ID
- **序列号**：同一毫秒内的序列号，防止 ID 重复

## 常见问题

### Q: 单机可以生成多少个 ID？

A: 取决于序列号位长。默认 10 位序列号表示单毫秒内最多生成 1024 个 ID，即 100 万个/秒。

### Q: 支持多少个工作节点？

A: 取决于工作节点 ID 位长。默认 10 位表示最多支持 1024 个节点。

### Q: 为什么异步初始化后调用方法失败？

A: 异步设置 workerId 时，Promise 还未完成，实例尚未初始化。建议在初始化完成后再发起请求。

### Q: 能否修改 workerId？

A: 创建中间件后，workerId 不可修改。需要修改时请重新创建中间件。

<!-- Refs -->

[npm-version-src]: https://img.shields.io/npm/v/@seepine/hono-snowflake
[npm-version-href]: https://www.npmjs.com/package/@seepine/hono-snowflake
[npm-downloads-src]: https://img.shields.io/npm/dm/@seepine/hono-snowflake
[npm-downloads-href]: https://npmjs.com/package/@seepine/hono-snowflake
[bundle-src]: https://img.shields.io/bundlephobia/minzip/@seepine/hono-snowflake
[bundle-href]: https://bundlephobia.com/result?p=@seepine/hono-snowflake
[license-src]: https://img.shields.io/github/license/seepine/hono-snowflake.svg
[license-href]: https://github.com/seepine/hono-snowflake/blob/main/LICENSE