@cdlab996/genid 1.2.1 → 1.3.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/dist/index.cjs CHANGED
@@ -1,31 +1,56 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
-
3
- //#region src/types/index.ts
4
- /**
5
- * ID 生成算法类型
6
- */
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/types.ts
3
+ /** ID 生成算法类型 */
7
4
  let GenidMethod = /* @__PURE__ */ function(GenidMethod) {
8
- /** 漂移算法(推荐用于高性能场景) */
5
+ /** 漂移算法(推荐,高并发下可突破每毫秒序列号上限) */
9
6
  GenidMethod[GenidMethod["DRIFT"] = 1] = "DRIFT";
10
- /** 传统算法 */
7
+ /** 传统算法(序列号耗尽时等待下一毫秒) */
11
8
  GenidMethod[GenidMethod["TRADITIONAL"] = 2] = "TRADITIONAL";
12
9
  return GenidMethod;
13
10
  }({});
14
-
15
11
  //#endregion
16
- //#region src/index.ts
12
+ //#region src/config.ts
13
+ /** 将用户配置与默认值合并,返回完整内部配置 */
14
+ function initConfig(options) {
15
+ const config = {
16
+ workerId: options.workerId,
17
+ method: options.method === GenidMethod.TRADITIONAL ? GenidMethod.TRADITIONAL : GenidMethod.DRIFT,
18
+ baseTime: options.baseTime && options.baseTime > 0 ? options.baseTime : (/* @__PURE__ */ new Date("2020-01-01")).valueOf(),
19
+ workerIdBitLength: options.workerIdBitLength && options.workerIdBitLength > 0 ? options.workerIdBitLength : 6,
20
+ seqBitLength: options.seqBitLength && options.seqBitLength > 0 ? options.seqBitLength : 6,
21
+ maxSeqNumber: 0,
22
+ minSeqNumber: 0,
23
+ topOverCostCount: 0
24
+ };
25
+ config.maxSeqNumber = options.maxSeqNumber && options.maxSeqNumber > 0 ? options.maxSeqNumber : (1 << config.seqBitLength) - 1;
26
+ config.minSeqNumber = options.minSeqNumber && options.minSeqNumber > 0 ? options.minSeqNumber : 5;
27
+ config.topOverCostCount = options.topOverCostCount && options.topOverCostCount > 0 ? options.topOverCostCount : 2e3;
28
+ return config;
29
+ }
30
+ /** 校验配置合法性,不合法则抛出 Error */
31
+ function validateConfig(config) {
32
+ const { workerId, baseTime, workerIdBitLength, seqBitLength, minSeqNumber, maxSeqNumber } = config;
33
+ if (baseTime > Date.now()) throw new Error("[GenidOptimized] baseTime 不能大于当前时间");
34
+ if (workerIdBitLength < 1 || workerIdBitLength > 15) throw new Error("[GenidOptimized] workerIdBitLength 必须在 1 到 15 之间");
35
+ if (seqBitLength < 3 || seqBitLength > 21) throw new Error("[GenidOptimized] seqBitLength 必须在 3 到 21 之间");
36
+ if (workerIdBitLength + seqBitLength > 22) throw new Error("[GenidOptimized] workerIdBitLength + seqBitLength 不能超过 22");
37
+ const maxWorkerId = (1 << workerIdBitLength) - 1;
38
+ if (workerId < 0 || workerId > maxWorkerId) throw new Error(`[GenidOptimized] workerId 必须在 0 到 ${maxWorkerId} 之间`);
39
+ if (minSeqNumber < 5) throw new Error("[GenidOptimized] minSeqNumber 必须至少为 5(0-4 保留)");
40
+ if (maxSeqNumber < minSeqNumber) throw new Error("[GenidOptimized] maxSeqNumber 必须大于或等于 minSeqNumber");
41
+ }
42
+ //#endregion
43
+ //#region src/genid.ts
17
44
  /**
18
- * 优化版 Snowflake ID 生成器
45
+ * 基于 Snowflake 算法的分布式唯一 ID 生成器
19
46
  *
20
- * 基于 Snowflake 算法的高性能分布式唯一 ID 生成器,支持漂移算法和时钟回拨处理。
47
+ * - 漂移算法:高并发下借用未来时间戳,突破每毫秒序列号上限
48
+ * - 时钟回拨:使用保留序列号(0-4)优雅降级,不阻塞生成
49
+ * - 非线程安全,每个 Worker/进程应使用独立实例和不同 workerId
21
50
  *
22
- * 特性:
23
- * - 漂移算法:提升高并发下的性能
24
- * - 优雅处理时钟回拨,不阻塞生成
25
- * - 可配置的位长度,灵活性高
26
- * - 支持传统和漂移两种生成方法
27
- *
28
- * ⚠️ 注意:此实例不是线程安全的,每个 Worker/进程应该创建独立的实例并使用不同的 workerId
51
+ * @example
52
+ * const genid = new GenidOptimized({ workerId: 1 });
53
+ * const id = genid.nextId();
29
54
  */
30
55
  var GenidOptimized = class {
31
56
  method;
@@ -44,29 +69,10 @@ var GenidOptimized = class {
44
69
  _isOverCost;
45
70
  _overCostCountInOneTerm;
46
71
  _stats;
47
- /**
48
- * 构造函数,初始化 ID 生成器
49
- *
50
- * @param {Object} options - 配置选项
51
- * @param {number} options.workerId - 工作节点/机器 ID(必须,范围 0 到 2^workerIdBitLength-1)
52
- * @param {GenidMethod} [options.method=GenidMethod.DRIFT] - 算法类型
53
- * @param {number} [options.baseTime=1577836800000] - 起始时间戳(毫秒,默认:2020-01-01)
54
- * @param {number} [options.workerIdBitLength=6] - 工作节点 ID 的位数(1-15,默认:6)
55
- * @param {number} [options.seqBitLength=6] - 序列号的位数(3-21,默认:6)
56
- * @param {number} [options.maxSeqNumber] - 最大序列号(默认:2^seqBitLength-1)
57
- * @param {number} [options.minSeqNumber=5] - 最小序列号(默认:5,0-4 保留)
58
- * @param {number} [options.topOverCostCount=2000] - 最大漂移次数(默认:2000)
59
- *
60
- * @throws {Error} 如果缺少 workerId 或配置无效
61
- *
62
- * @example
63
- * const genid = new GenidOptimized({ workerId: 1 });
64
- * const id = genid.nextId();
65
- */
66
72
  constructor(options) {
67
73
  if (options.workerId === void 0 || options.workerId === null) throw new Error("[GenidOptimized] workerId 是必须参数");
68
- const config = this._initConfig(options);
69
- this._validateConfig(config);
74
+ const config = initConfig(options);
75
+ validateConfig(config);
70
76
  this._initVariables(config);
71
77
  this._stats = {
72
78
  totalGenerated: 0n,
@@ -75,49 +81,6 @@ var GenidOptimized = class {
75
81
  startTime: Date.now()
76
82
  };
77
83
  }
78
- /**
79
- * 初始化配置,设置默认值
80
- * @private
81
- * @param {Object} options - 用户提供的配置
82
- * @returns {Object} 合并后的配置对象
83
- */
84
- _initConfig(options) {
85
- const config = {
86
- workerId: options.workerId,
87
- method: options.method === GenidMethod.TRADITIONAL ? GenidMethod.TRADITIONAL : GenidMethod.DRIFT,
88
- baseTime: options.baseTime && options.baseTime > 0 ? options.baseTime : (/* @__PURE__ */ new Date("2020-01-01")).valueOf(),
89
- workerIdBitLength: options.workerIdBitLength && options.workerIdBitLength > 0 ? options.workerIdBitLength : 6,
90
- seqBitLength: options.seqBitLength && options.seqBitLength > 0 ? options.seqBitLength : 6,
91
- maxSeqNumber: 0,
92
- minSeqNumber: 0,
93
- topOverCostCount: 0
94
- };
95
- config.maxSeqNumber = options.maxSeqNumber && options.maxSeqNumber > 0 ? options.maxSeqNumber : (1 << config.seqBitLength) - 1;
96
- config.minSeqNumber = options.minSeqNumber && options.minSeqNumber > 0 ? options.minSeqNumber : 5;
97
- config.topOverCostCount = options.topOverCostCount && options.topOverCostCount > 0 ? options.topOverCostCount : 2e3;
98
- return config;
99
- }
100
- /**
101
- * 验证配置参数的有效性
102
- * @private
103
- * @param {Object} config - 配置对象
104
- * @throws {Error} 如果配置无效
105
- */
106
- _validateConfig(config) {
107
- const { workerId, workerIdBitLength, seqBitLength, minSeqNumber, maxSeqNumber } = config;
108
- if (workerIdBitLength < 1 || workerIdBitLength > 15) throw new Error("[GenidOptimized] workerIdBitLength 必须在 1 到 15 之间");
109
- if (seqBitLength < 3 || seqBitLength > 21) throw new Error("[GenidOptimized] seqBitLength 必须在 3 到 21 之间");
110
- if (workerIdBitLength + seqBitLength > 22) throw new Error("[GenidOptimized] workerIdBitLength + seqBitLength 不能超过 22");
111
- const maxWorkerId = (1 << workerIdBitLength) - 1;
112
- if (workerId < 0 || workerId > maxWorkerId) throw new Error(`[GenidOptimized] workerId 必须在 0 到 ${maxWorkerId} 之间`);
113
- if (minSeqNumber < 5) throw new Error("[GenidOptimized] minSeqNumber 必须至少为 5(0-4 保留)");
114
- if (maxSeqNumber < minSeqNumber) throw new Error("[GenidOptimized] maxSeqNumber 必须大于或等于 minSeqNumber");
115
- }
116
- /**
117
- * 初始化实例变量
118
- * @private
119
- * @param {Object} config - 配置对象
120
- */
121
84
  _initVariables(config) {
122
85
  this.method = BigInt(config.method);
123
86
  this.baseTime = BigInt(config.baseTime);
@@ -135,64 +98,37 @@ var GenidOptimized = class {
135
98
  this._isOverCost = false;
136
99
  this._overCostCountInOneTerm = 0n;
137
100
  }
138
- /**
139
- * 获取当前时间戳(相对于 baseTime 的毫秒数)
140
- * @private
141
- * @returns {bigint} 当前时间戳
142
- */
101
+ /** 获取相对于 baseTime 的当前时间戳 */
143
102
  _getCurrentTimeTick() {
144
103
  return BigInt(Date.now()) - this.baseTime;
145
104
  }
146
- /**
147
- * 等待下一毫秒
148
- * @private
149
- * @returns {bigint} 下一毫秒时间戳
150
- */
105
+ /** 自旋等待直到时间前进到下一毫秒 */
151
106
  _getNextTimeTick() {
152
107
  let timeTick = this._getCurrentTimeTick();
153
108
  let spinCount = 0;
154
109
  const maxSpinCount = 1e6;
155
110
  while (timeTick <= this._lastTimeTick) {
156
111
  spinCount++;
157
- if (spinCount > maxSpinCount)
158
- /**
159
- * 如果自旋太多次,强制返回当前时间 + 1
160
- * 这种情况理论上不应该发生,除非系统时间出现严重问题
161
- */
162
- return this._lastTimeTick + 1n;
112
+ if (spinCount > maxSpinCount) return this._lastTimeTick + 1n;
163
113
  timeTick = this._getCurrentTimeTick();
164
114
  }
165
115
  return timeTick;
166
116
  }
167
- /**
168
- * 根据组件计算 ID
169
- * @private
170
- * @param {bigint} useTimeTick - 使用的时间戳
171
- * @returns {bigint} 计算得到的 ID
172
- */
117
+ /** 组装 ID:timestamp | workerId | sequence,并自增序列号 */
173
118
  _calcId(useTimeTick) {
174
119
  const result = (BigInt(useTimeTick) << this._timestampShift) + (this.workerId << this.seqBitLength) + this._currentSeqNumber;
175
120
  this._currentSeqNumber++;
176
121
  this._stats.totalGenerated++;
177
122
  return result;
178
123
  }
179
- /**
180
- * 计算时钟回拨时的 ID
181
- * @private
182
- * @param {bigint} useTimeTick - 使用的时间戳
183
- * @returns {bigint} 计算得到的 ID
184
- */
124
+ /** 时钟回拨时组装 ID,使用保留序列号(0-4)避免冲突 */
185
125
  _calcTurnBackId(useTimeTick) {
186
126
  const result = (BigInt(useTimeTick) << this._timestampShift) + (this.workerId << this.seqBitLength) + BigInt(this._turnBackIndex);
187
127
  this._turnBackTimeTick++;
188
128
  this._stats.totalGenerated++;
189
129
  return result;
190
130
  }
191
- /**
192
- * 处理漂移情况(漂移算法)
193
- * @private
194
- * @returns {bigint} 生成的 ID
195
- */
131
+ /** 漂移状态下生成 ID */
196
132
  _nextOverCostId() {
197
133
  const currentTimeTick = this._getCurrentTimeTick();
198
134
  if (currentTimeTick > this._lastTimeTick) {
@@ -228,11 +164,7 @@ var GenidOptimized = class {
228
164
  }
229
165
  return this._calcId(this._lastTimeTick);
230
166
  }
231
- /**
232
- * 正常生成 ID
233
- * @private
234
- * @returns {bigint} 生成的 ID
235
- */
167
+ /** 正常状态下生成 ID */
236
168
  _nextNormalId() {
237
169
  const currentTimeTick = this._getCurrentTimeTick();
238
170
  if (currentTimeTick < this._lastTimeTick) {
@@ -249,6 +181,13 @@ var GenidOptimized = class {
249
181
  this._beginTurnBackAction(this._turnBackTimeTick);
250
182
  this._stats.turnBackCount++;
251
183
  }
184
+ if (this._turnBackTimeTick >= this._lastTimeTick) {
185
+ this._turnBackTimeTick = 0n;
186
+ this._turnBackIndex = 0;
187
+ this._lastTimeTick = this._getNextTimeTick();
188
+ this._currentSeqNumber = this.minSeqNumber;
189
+ return this._calcId(this._lastTimeTick);
190
+ }
252
191
  return this._calcTurnBackId(this._turnBackTimeTick);
253
192
  }
254
193
  if (this._turnBackTimeTick > 0) {
@@ -262,6 +201,11 @@ var GenidOptimized = class {
262
201
  return this._calcId(this._lastTimeTick);
263
202
  }
264
203
  if (this._currentSeqNumber > this.maxSeqNumber) {
204
+ if (this.method === BigInt(GenidMethod.TRADITIONAL)) {
205
+ this._lastTimeTick = this._getNextTimeTick();
206
+ this._currentSeqNumber = this.minSeqNumber;
207
+ return this._calcId(this._lastTimeTick);
208
+ }
265
209
  this._beginOverCostAction(currentTimeTick);
266
210
  this._lastTimeTick++;
267
211
  this._currentSeqNumber = this.minSeqNumber;
@@ -272,83 +216,29 @@ var GenidOptimized = class {
272
216
  }
273
217
  return this._calcId(this._lastTimeTick);
274
218
  }
219
+ _beginOverCostAction(_useTimeTick) {}
220
+ _endOverCostAction(_useTimeTick) {}
221
+ _beginTurnBackAction(_useTimeTick) {}
222
+ _endTurnBackAction(_useTimeTick) {}
275
223
  /**
276
- * 钩子函数:开始漂移操作(可被子类重写)
277
- * @protected
278
- * @param {bigint} useTimeTick - 当前时间戳
279
- */
280
- _beginOverCostAction(useTimeTick) {}
281
- /**
282
- * 钩子函数:结束漂移操作(可被子类重写)
283
- * @protected
284
- * @param {bigint} useTimeTick - 当前时间戳
285
- */
286
- _endOverCostAction(useTimeTick) {}
287
- /**
288
- * 钩子函数:开始时钟回拨操作(可被子类重写)
289
- * @protected
290
- * @param {bigint} useTimeTick - 当前时间戳
291
- */
292
- _beginTurnBackAction(useTimeTick) {}
293
- /**
294
- * 钩子函数:结束时钟回拨操作(可被子类重写)
295
- * @protected
296
- * @param {bigint} useTimeTick - 当前时间戳
297
- */
298
- _endTurnBackAction(useTimeTick) {}
299
- /**
300
- * 生成下一个 ID
301
- *
302
- * @returns {number} 唯一 ID(Number 类型)
303
- * @throws {Error} 如果 ID 超出 JavaScript 安全整数范围
304
- *
305
- * @example
306
- * const id = genid.nextNumber();
307
- * console.log(id); // 123456789012345
224
+ * 生成 ID,返回 number。超出安全整数范围时抛错。
225
+ * @throws 当 ID >= Number.MAX_SAFE_INTEGER + 1 时
308
226
  */
309
227
  nextNumber() {
310
228
  const id = this._isOverCost ? this._nextOverCostId() : this._nextNormalId();
311
229
  if (id >= 9007199254740992n) throw new Error(`[GenidOptimized] 生成的 ID ${id.toString()} 超出 JavaScript 安全整数范围 (9007199254740992)。请使用 nextBigId() 方法。`);
312
230
  return Number(id);
313
231
  }
314
- /**
315
- * 生成下一个 ID
316
- *
317
- * 如果 ID 在安全范围内返回 Number,否则返回 BigInt
318
- *
319
- * @returns {number|bigint} 唯一 ID
320
- *
321
- * @example
322
- * const id = genid.nextId();
323
- * console.log(typeof id); // 'number' 或 'bigint'
324
- */
232
+ /** 生成 ID,安全范围内返回 number,否则返回 bigint */
325
233
  nextId() {
326
234
  const id = this._isOverCost ? this._nextOverCostId() : this._nextNormalId();
327
235
  return id >= 9007199254740992n ? id : Number(id);
328
236
  }
329
- /**
330
- * 生成下一个 ID
331
- *
332
- * @returns {bigint} 唯一 ID(BigInt 类型)
333
- *
334
- * @example
335
- * const id = genid.nextBigId();
336
- * console.log(id); // 123456789012345678n
337
- */
237
+ /** 生成 ID,始终返回 bigint */
338
238
  nextBigId() {
339
239
  return this._isOverCost ? this._nextOverCostId() : this._nextNormalId();
340
240
  }
341
- /**
342
- * 批量生成 ID
343
- *
344
- * @param {number} count - 要生成的 ID 数量
345
- * @param {boolean} [asBigInt=false] - 是否返回 BigInt 数组
346
- * @returns {Array<number|bigint>} 唯一 ID 数组
347
- *
348
- * @example
349
- * const ids = genid.nextBatch(100);
350
- * const bigIds = genid.nextBatch(100, true);
351
- */
241
+ /** 批量生成 ID */
352
242
  nextBatch(count, asBigInt = false) {
353
243
  if (count <= 0) throw new Error("[GenidOptimized] 批量生成数量必须大于 0");
354
244
  const ids = [];
@@ -356,24 +246,11 @@ var GenidOptimized = class {
356
246
  return ids;
357
247
  }
358
248
  /**
359
- * 解析 ID,提取其组成部分
360
- *
361
- * @param {number|bigint|string} id - 要解析的 ID
362
- * @returns {Object} 解析结果
363
- * @returns {Date} return.timestamp - 生成时间戳
364
- * @returns {number} return.timestampMs - 时间戳(毫秒)
365
- * @returns {number} return.workerId - 工作节点 ID
366
- * @returns {number} return.sequence - 序列号
249
+ * 解析 ID,提取时间戳、workerId、序列号
367
250
  *
368
251
  * @example
369
- * const info = genid.parse(id);
370
- * console.log(info);
371
- * // {
372
- * // timestamp: Date,
373
- * // timestampMs: 1609459200000,
374
- * // workerId: 1,
375
- * // sequence: 42
376
- * // }
252
+ * genid.parse(id)
253
+ * // { timestamp: Date, timestampMs: 1609459200000, workerId: 1, sequence: 42 }
377
254
  */
378
255
  parse(id) {
379
256
  const idBigInt = BigInt(id);
@@ -389,15 +266,7 @@ var GenidOptimized = class {
389
266
  sequence: Number(sequence)
390
267
  };
391
268
  }
392
- /**
393
- * 获取生成器统计信息
394
- *
395
- * @returns {Object} 统计数据
396
- *
397
- * @example
398
- * const stats = genid.getStats();
399
- * console.log(stats);
400
- */
269
+ /** 获取运行统计信息 */
401
270
  getStats() {
402
271
  const uptime = Date.now() - this._stats.startTime;
403
272
  const totalGenerated = Number(this._stats.totalGenerated);
@@ -410,9 +279,7 @@ var GenidOptimized = class {
410
279
  currentState: this._isOverCost ? "OVER_COST" : "NORMAL"
411
280
  };
412
281
  }
413
- /**
414
- * 重置统计数据
415
- */
282
+ /** 重置统计数据 */
416
283
  resetStats() {
417
284
  this._stats = {
418
285
  totalGenerated: 0n,
@@ -421,11 +288,7 @@ var GenidOptimized = class {
421
288
  startTime: Date.now()
422
289
  };
423
290
  }
424
- /**
425
- * 获取配置信息
426
- *
427
- * @returns {Object} 配置详情
428
- */
291
+ /** 获取当前配置信息 */
429
292
  getConfig() {
430
293
  const maxWorkerId = (1 << Number(this.workerIdBitLength)) - 1;
431
294
  const maxSequence = (1 << Number(this.seqBitLength)) - 1;
@@ -444,18 +307,8 @@ var GenidOptimized = class {
444
307
  };
445
308
  }
446
309
  /**
447
- * 验证 ID 是否为有效的 Snowflake ID
448
- *
449
- * @param {number|bigint|string} id - 要验证的 ID
450
- * @param {boolean} [strictWorkerId=false] - 是否严格验证 workerId 必须匹配当前实例
451
- * @returns {boolean} ID 是否有效
452
- *
453
- * @example
454
- * const genid = new GenidOptimized({ workerId: 1 });
455
- * const id = genid.nextId();
456
- * genid.isValid(id); // true
457
- * genid.isValid(12345); // false
458
- * genid.isValid(id, true); // true (workerId 匹配)
310
+ * 验证 ID 是否为当前配置下合法的 Snowflake ID
311
+ * @param strictWorkerId - 为 true 时要求 workerId 匹配当前实例
459
312
  */
460
313
  isValid(id, strictWorkerId = false) {
461
314
  try {
@@ -478,12 +331,7 @@ var GenidOptimized = class {
478
331
  return false;
479
332
  }
480
333
  }
481
- /**
482
- * 将 ID 格式化为二进制字符串以便调试
483
- *
484
- * @param {number|bigint|string} id - 要格式化的 ID
485
- * @returns {string} 格式化的二进制表示
486
- */
334
+ /** 将 ID 格式化为带标注的二进制字符串(调试用) */
487
335
  formatBinary(id) {
488
336
  const idBigInt = BigInt(id);
489
337
  if (idBigInt < 0n) throw new Error("[GenidOptimized] ID 不能为负数");
@@ -501,6 +349,6 @@ var GenidOptimized = class {
501
349
  ].join("\n");
502
350
  }
503
351
  };
504
-
505
352
  //#endregion
506
- exports.GenidOptimized = GenidOptimized;
353
+ exports.GenidMethod = GenidMethod;
354
+ exports.GenidOptimized = GenidOptimized;