flycode-mcp 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -4
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/common.js +61 -0
- package/dist/tools/common.js.map +1 -0
- package/dist/utils/snowflake.js +119 -0
- package/dist/utils/snowflake.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for the
|
|
|
11
11
|
- 基于官方 `@modelcontextprotocol/sdk` 实现,使用标准 `stdio` 传输协议。
|
|
12
12
|
- 启动即完成 APaaS IDE 平台鉴权链路:账号登录 → 获取租户信息 → 获取 IDE Token。
|
|
13
13
|
- 内置统一请求层 `request`,自动按请求类型(`center` / `tenant`)切换中心服务地址与当前租户连接地址,并自动注入鉴权 Token。
|
|
14
|
-
- 当前提供工具:业务逻辑类 `page_model_logic_list`(分页查询业务逻辑列表)、`get_model_logic`(查询单个业务逻辑详情)、`save_model_logic`(保存 / 更新业务逻辑完整 JSON)、`simple_save_flycode_model_logic`(轻量保存 flycode 业务逻辑,只传 `modelLogicCode` / `flycode` / 可选 `input` / `output`);实体类 `page_entity_list`(分页查询实体列表)、`get_entity`(查询实体详情);表单 / 页面类 `page_form_list`(分页查询表单 / 页面列表)、`get_form`(查询表单 /
|
|
14
|
+
- 当前提供工具:业务逻辑类 `page_model_logic_list`(分页查询业务逻辑列表)、`get_model_logic`(查询单个业务逻辑详情)、`save_model_logic`(保存 / 更新业务逻辑完整 JSON)、`simple_save_flycode_model_logic`(轻量保存 flycode 业务逻辑,只传 `modelLogicCode` / `flycode` / 可选 `input` / `output`);实体类 `page_entity_list`(分页查询实体列表)、`get_entity`(查询实体详情);表单 / 页面类 `page_form_list`(分页查询表单 / 页面列表)、`get_form`(查询表单 / 页面详情);通用类 `generate_unique_code`(生成唯一编码,用于新建实体 / 领域 / 表单时生成 JSON 中的 `code` 字段)。
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -240,6 +240,22 @@ username=<账号>&password=<密码>&tenantCode=<租户号>&envName=<环境名>
|
|
|
240
240
|
|
|
241
241
|
> 注:工具的 `description` 中附有「字段速查」,列出了各顶层对象的关键字段与编码枚举含义(如 `pageinfo.type` 页面类型、`marktype` 创建标记、`clientcategorycode` 用户端等),便于理解返回 JSON。详情类型的字段定义见 `src/clients/formClient.ts`(`FormResult` / `FormPageInfo` / `FormViewNode` / `FormControl` 等接口)。
|
|
242
242
|
|
|
243
|
+
### `generate_unique_code` — 生成唯一编码
|
|
244
|
+
|
|
245
|
+
通过雪花算法(`src/utils/snowflake.ts`)生成一个全局唯一 ID(code)。在新建实体、领域、表单等内容时,其 JSON 字段中通常需要携带一个唯一 `code`(如实体的 `objectcode`、表单的 `code` 等),可调用本工具获取并填入。底层直接调用 snowflake 实例的 `nextId()`。
|
|
246
|
+
|
|
247
|
+
**输入参数:**
|
|
248
|
+
|
|
249
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
250
|
+
| ------- | ------ | ---- | ---------------------------------------------------------------------------- |
|
|
251
|
+
| `prefix`| string | 否 | 可选前缀,拼接到生成的唯一 ID 之前(例如实体编码前缀);不传则只返回纯数字 ID 字符串 |
|
|
252
|
+
|
|
253
|
+
**返回:** 一个 JSON 对象 `{ "code": "..." }`:
|
|
254
|
+
|
|
255
|
+
- `code`:生成的唯一编码。以**字符串**形式返回,避免雪花 ID 超过 `Number.MAX_SAFE_INTEGER` 时的大整数精度丢失。
|
|
256
|
+
|
|
257
|
+
> 注:本工具仅在本地生成 ID,**不修改任何服务端数据**,且每次调用返回不同的 ID(非幂等)。如需带固定前缀的编码(如 `kx_877483974950260736`),传入 `prefix` 即可。
|
|
258
|
+
|
|
243
259
|
---
|
|
244
260
|
|
|
245
261
|
## 项目结构
|
|
@@ -261,18 +277,20 @@ flycode-mcp/
|
|
|
261
277
|
│ │ ├── token.ts # 鉴权 Token 存储器
|
|
262
278
|
│ │ └── tenant.ts # 当前租户及连接信息存储器
|
|
263
279
|
│ ├── tools/ # 按能力分类的 MCP 工具定义
|
|
280
|
+
│ │ ├── common.ts # 通用工具(generate_unique_code:雪花算法生成唯一编码)
|
|
264
281
|
│ │ ├── logic/
|
|
265
282
|
│ │ │ ├── read.ts # 只读类工具(page_model_logic_list / get_model_logic)
|
|
266
283
|
│ │ │ ├── write.ts # 写入类工具(save_model_logic / simple_save_model_logic)
|
|
267
284
|
│ │ │ └── schemas.ts # 业务逻辑共享 zod schema(LogicResult / 参数 / operations / bindjson)
|
|
268
|
-
│ │
|
|
269
|
-
│ │
|
|
285
|
+
│ │ ├── entity/
|
|
286
|
+
│ │ │ └── read.ts # 只读类工具(page_entity_list / get_entity)
|
|
270
287
|
│ │ └── form/
|
|
271
288
|
│ │ └── read.ts # 只读类工具(page_form_list / get_form)
|
|
272
289
|
│ └── utils/
|
|
273
290
|
│ ├── config.ts # 从命令行参数解析连接配置(BASE_URL / 账号等)
|
|
274
291
|
│ ├── request.ts # 统一 axios 请求层(中心/租户地址切换 + Token 注入)
|
|
275
292
|
│ ├── mcp-types.ts # MCP 工具统一定义类型 ToolDef
|
|
293
|
+
│ ├── snowflake.ts # 雪花算法 ID 生成器(generate_unique_code 依赖)
|
|
276
294
|
│ └── date.ts # 日期格式化工具(saverecord 提交时间用)
|
|
277
295
|
├── dist/ # 编译产物(由 tsc 生成,已忽略)
|
|
278
296
|
├── package.json
|
|
@@ -288,7 +306,7 @@ flycode-mcp/
|
|
|
288
306
|
2. **登录**:`service/auth.ts` 中的 `authenticate()` 调用 `/api/multiplat/auth/login` 获取 Token,存入内存。
|
|
289
307
|
3. **定位租户与环境**:`authenticate()` 调用 `/api/multiplat/auth/getTenantInfo`,依据 `tenantCode + envName` 匹配出目标租户,保存其连接信息(`conn.config`)到内存。
|
|
290
308
|
4. **获取 IDE Token**:`authenticate()` 调用 `/api/multiplat/auth/getIdeToken` 换取 IDE 专用 Token 并覆盖内存中的 Token。
|
|
291
|
-
5. **注册并启动**:创建 `McpServer`,注册 `page_model_logic_list`、`get_model_logic`、`save_model_logic`、`simple_save_flycode_model_logic`、`page_entity_list`、`get_entity`、`page_form_list`、`get_form` 等工具,通过 `StdioServerTransport` 监听请求。
|
|
309
|
+
5. **注册并启动**:创建 `McpServer`,注册 `page_model_logic_list`、`get_model_logic`、`save_model_logic`、`simple_save_flycode_model_logic`、`page_entity_list`、`get_entity`、`page_form_list`、`get_form`、`generate_unique_code` 等工具,通过 `StdioServerTransport` 监听请求。
|
|
292
310
|
6. **业务请求**:工具被调用时,`logicClient` / `entityClient` / `formClient` 通过 `request({ type: "tenant" })` 自动切换到当前租户连接地址,并携带已注入的 Token 发起查询。
|
|
293
311
|
|
|
294
312
|
---
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { readTools as logicReadTools } from './tools/logic/read.js';
|
|
|
6
6
|
import { writeTools as logicWriteTools } from './tools/logic/write.js';
|
|
7
7
|
import { readTools as entityReadTools } from './tools/entity/read.js';
|
|
8
8
|
import { readTools as formReadTools } from './tools/form/read.js';
|
|
9
|
+
import { commonTools } from './tools/common.js';
|
|
9
10
|
// 鉴权初始化(登录 -> 获取租户信息 -> 获取 IDE Token)
|
|
10
11
|
await authenticate();
|
|
11
12
|
// 创建 MCP 服务器
|
|
@@ -19,6 +20,7 @@ const allTools = [
|
|
|
19
20
|
...logicWriteTools,
|
|
20
21
|
...entityReadTools,
|
|
21
22
|
...formReadTools,
|
|
23
|
+
...commonTools,
|
|
22
24
|
];
|
|
23
25
|
for (const t of allTools) {
|
|
24
26
|
server.registerTool(t.name, t.config, t.handler);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,OAAO,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,OAAO,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,sCAAsC;AACtC,MAAM,YAAY,EAAE,CAAA;AAEpB,aAAa;AACb,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAA;AAEF,uCAAuC;AACvC,MAAM,QAAQ,GAAc;IAC1B,GAAG,cAAc;IACjB,GAAG,eAAe;IAClB,GAAG,eAAe;IAClB,GAAG,aAAa;IAChB,GAAG,WAAW;CACf,CAAA;AAED,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;IACzB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;AAClD,CAAC;AAED,OAAO;AACP,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/B,kBAAkB;IAClB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;AACjD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { nextId } from '../utils/snowflake.js';
|
|
3
|
+
/**
|
|
4
|
+
* 通用工具:生成唯一编码(code)。
|
|
5
|
+
*
|
|
6
|
+
* 在新建实体、领域、表单等内容时,其 JSON 字段中通常需要携带一个唯一
|
|
7
|
+
* code(如实体的 objectcode、领域的 objecttypecode、表单的 formcode 等)。
|
|
8
|
+
* 本工具借助 @utils/snowflake 的雪花算法生成全局唯一 ID 作为该 code,
|
|
9
|
+
* 以字符串形式返回以避免超过 Number.MAX_SAFE_INTEGER 时的大整数精度丢失。
|
|
10
|
+
*/
|
|
11
|
+
export const commonTools = [
|
|
12
|
+
{
|
|
13
|
+
name: 'generate_unique_code',
|
|
14
|
+
config: {
|
|
15
|
+
title: '生成唯一编码',
|
|
16
|
+
description: '通过雪花算法(snowflake)生成一个全局唯一 ID(code)。在新建实体、领域、表单等内容时,其 JSON 字段中通常需要携带一个唯一 code,可调用本工具获取。',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
prefix: z.string().optional().describe('可选前缀,拼接到生成的唯一 ID 之前(例如实体编码前缀);不传则只返回纯数字 ID 字符串')
|
|
19
|
+
},
|
|
20
|
+
outputSchema: {
|
|
21
|
+
code: z.string().describe('生成的唯一编码(code)。字符串形式以避免大整数精度丢失')
|
|
22
|
+
},
|
|
23
|
+
annotations: {
|
|
24
|
+
readOnlyHint: true, // 仅本地生成 ID,不修改任何服务端数据
|
|
25
|
+
destructiveHint: false, // 无破坏性
|
|
26
|
+
idempotentHint: false // 每次调用返回不同 ID
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
handler: async (args) => {
|
|
30
|
+
const { prefix = '' } = args;
|
|
31
|
+
try {
|
|
32
|
+
const id = nextId().toString();
|
|
33
|
+
const code = prefix ? `${prefix}${id}` : id;
|
|
34
|
+
const result = { code };
|
|
35
|
+
return {
|
|
36
|
+
content: [{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: JSON.stringify(result)
|
|
39
|
+
}],
|
|
40
|
+
// outputSchema 已在工具上声明,SDK 1.30 要求调用结果必须携带
|
|
41
|
+
// structuredContent 与之匹配,否则会抛 -32602;这里同时返回
|
|
42
|
+
// 文本(给人/模型阅读)和结构化内容(供 schema 校验)。
|
|
43
|
+
structuredContent: result
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
// 雪花算法在时钟回拨过大等异常情况下会抛错,原样返回错误信息。
|
|
48
|
+
const err = e;
|
|
49
|
+
const body = { error: err.message ?? String(e) };
|
|
50
|
+
return {
|
|
51
|
+
isError: true,
|
|
52
|
+
content: [{
|
|
53
|
+
type: 'text',
|
|
54
|
+
text: JSON.stringify(body)
|
|
55
|
+
}]
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/tools/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAE9C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAc;IACpC;QACE,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE;YACN,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,wFAAwF;YACrG,WAAW,EAAE;gBACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;aACzF;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;aAC3D;YACD,WAAW,EAAE;gBACX,YAAY,EAAE,IAAI,EAAO,sBAAsB;gBAC/C,eAAe,EAAE,KAAK,EAAG,OAAO;gBAChC,cAAc,EAAE,KAAK,CAAI,cAAc;aACxC;SACF;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACtB,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,IAAI,CAAA;YAC5B,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAA;gBAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;gBAC3C,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAA;gBACvB,OAAO;oBACL,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;yBAC7B,CAAC;oBACF,2CAA2C;oBAC3C,4CAA4C;oBAC5C,kCAAkC;oBAClC,iBAAiB,EAAE,MAA4C;iBAChE,CAAA;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,iCAAiC;gBACjC,MAAM,GAAG,GAAG,CAAyB,CAAA;gBACrC,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;gBAChD,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;yBAC3B,CAAC;iBACH,CAAA;YACH,CAAC;QACH,CAAC;KACF;CACF,CAAA"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 雪花算法 ID 生成器(无分号风格)
|
|
3
|
+
* 结构: 1 位符号位 + 41 位时间戳(毫秒) + 10 位机器 ID + 12 位序列号
|
|
4
|
+
* 默认纪元: 2020-01-01 00:00:00 UTC
|
|
5
|
+
*/
|
|
6
|
+
class Snowflake {
|
|
7
|
+
// 各部分的位数
|
|
8
|
+
workerIdBits = 5;
|
|
9
|
+
datacenterIdBits = 5;
|
|
10
|
+
sequenceBits = 12;
|
|
11
|
+
// 最大取值
|
|
12
|
+
maxWorkerId = -1 ^ (-1 << this.workerIdBits); // 31
|
|
13
|
+
maxDatacenterId = -1 ^ (-1 << this.datacenterIdBits); // 31
|
|
14
|
+
sequenceMask = -1 ^ (-1 << this.sequenceBits); // 4095
|
|
15
|
+
// 左移位数
|
|
16
|
+
workerIdShift = this.sequenceBits; // 12
|
|
17
|
+
datacenterIdShift = this.sequenceBits + this.workerIdBits; // 17
|
|
18
|
+
timestampShift = this.sequenceBits + this.workerIdBits + this.datacenterIdBits; // 22
|
|
19
|
+
// 自定义纪元(毫秒时间戳)
|
|
20
|
+
epoch;
|
|
21
|
+
// 上次生成时间戳及序列号
|
|
22
|
+
lastTimestamp = -1n;
|
|
23
|
+
sequence = 0n;
|
|
24
|
+
// 机器 ID 和数据中心 ID
|
|
25
|
+
workerId;
|
|
26
|
+
datacenterId;
|
|
27
|
+
/**
|
|
28
|
+
* @param workerId 机器 ID (0 ~ 31)
|
|
29
|
+
* @param datacenterId 数据中心 ID (0 ~ 31)
|
|
30
|
+
* @param epoch 自定义纪元(毫秒),默认 2020-01-01 00:00:00 UTC
|
|
31
|
+
*/
|
|
32
|
+
constructor(workerId, datacenterId, epoch = 1577836800000) {
|
|
33
|
+
if (workerId > this.maxWorkerId || workerId < 0) {
|
|
34
|
+
throw new Error(`workerId 必须在 0 ~ ${this.maxWorkerId} 之间`);
|
|
35
|
+
}
|
|
36
|
+
if (datacenterId > this.maxDatacenterId || datacenterId < 0) {
|
|
37
|
+
throw new Error(`datacenterId 必须在 0 ~ ${this.maxDatacenterId} 之间`);
|
|
38
|
+
}
|
|
39
|
+
this.workerId = BigInt(workerId);
|
|
40
|
+
this.datacenterId = BigInt(datacenterId);
|
|
41
|
+
this.epoch = BigInt(epoch);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 生成下一个唯一 ID (BigInt)
|
|
45
|
+
*/
|
|
46
|
+
nextId() {
|
|
47
|
+
let timestamp = this.currentTimestamp();
|
|
48
|
+
// 时钟回拨处理:等待或抛异常
|
|
49
|
+
if (timestamp < this.lastTimestamp) {
|
|
50
|
+
const offset = this.lastTimestamp - timestamp;
|
|
51
|
+
if (offset <= 5n) {
|
|
52
|
+
while (timestamp < this.lastTimestamp) {
|
|
53
|
+
timestamp = this.currentTimestamp();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
throw new Error(`时钟回拨过大: ${offset}ms,无法生成 ID`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 同一毫秒内序列号递增
|
|
61
|
+
if (timestamp === this.lastTimestamp) {
|
|
62
|
+
this.sequence = (this.sequence + 1n) & BigInt(this.sequenceMask);
|
|
63
|
+
if (this.sequence === 0n) {
|
|
64
|
+
timestamp = this.waitNextMillis(this.lastTimestamp);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
this.sequence = 0n;
|
|
69
|
+
}
|
|
70
|
+
this.lastTimestamp = timestamp;
|
|
71
|
+
// 拼装 ID
|
|
72
|
+
const id = ((timestamp - this.epoch) << BigInt(this.timestampShift)) |
|
|
73
|
+
(this.datacenterId << BigInt(this.datacenterIdShift)) |
|
|
74
|
+
(this.workerId << BigInt(this.workerIdShift)) |
|
|
75
|
+
this.sequence;
|
|
76
|
+
return id;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 等待直到下一毫秒
|
|
80
|
+
*/
|
|
81
|
+
waitNextMillis(lastTimestamp) {
|
|
82
|
+
let timestamp = this.currentTimestamp();
|
|
83
|
+
while (timestamp <= lastTimestamp) {
|
|
84
|
+
timestamp = this.currentTimestamp();
|
|
85
|
+
}
|
|
86
|
+
return timestamp;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 当前毫秒时间戳
|
|
90
|
+
*/
|
|
91
|
+
currentTimestamp() {
|
|
92
|
+
return BigInt(Date.now());
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 解析 ID 各组成部分
|
|
96
|
+
*/
|
|
97
|
+
parse(id) {
|
|
98
|
+
const timestamp = (id >> BigInt(this.timestampShift)) + this.epoch;
|
|
99
|
+
const datacenterId = (id >> BigInt(this.datacenterIdShift)) & BigInt(this.maxDatacenterId);
|
|
100
|
+
const workerId = (id >> BigInt(this.workerIdShift)) & BigInt(this.maxWorkerId);
|
|
101
|
+
const sequence = id & BigInt(this.sequenceMask);
|
|
102
|
+
return {
|
|
103
|
+
timestamp,
|
|
104
|
+
datacenterId,
|
|
105
|
+
workerId,
|
|
106
|
+
sequence,
|
|
107
|
+
generateTime: new Date(Number(timestamp))
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** workerId */
|
|
112
|
+
export const WORKER_ID = 1;
|
|
113
|
+
/** datacenterId */
|
|
114
|
+
export const DATACENTER_ID = 1;
|
|
115
|
+
/** Snowflake 实例 */
|
|
116
|
+
export const snowflake = new Snowflake(WORKER_ID, DATACENTER_ID);
|
|
117
|
+
/** 生成 ID 方法(箭头函数保持 this 绑定,避免作为独立引用调用时丢失实例) */
|
|
118
|
+
export const nextId = () => snowflake.nextId();
|
|
119
|
+
//# sourceMappingURL=snowflake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snowflake.js","sourceRoot":"","sources":["../../src/utils/snowflake.ts"],"names":[],"mappings":"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"}
|