@venizia/ignis-helpers 0.0.4-0 → 0.0.4-1
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/helpers/index.d.ts +1 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/index.js.map +1 -1
- package/dist/helpers/uid/helper.d.ts +117 -0
- package/dist/helpers/uid/helper.d.ts.map +1 -0
- package/dist/helpers/uid/helper.js +246 -0
- package/dist/helpers/uid/helper.js.map +1 -0
- package/dist/helpers/uid/index.d.ts +2 -0
- package/dist/helpers/uid/index.d.ts.map +1 -0
- package/dist/helpers/uid/index.js +18 -0
- package/dist/helpers/uid/index.js.map +1 -0
- package/package.json +1 -1
package/dist/helpers/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,iBAAiB,CAAC"}
|
package/dist/helpers/index.js
CHANGED
|
@@ -26,5 +26,6 @@ __exportStar(require("./redis"), exports);
|
|
|
26
26
|
__exportStar(require("./socket-io"), exports);
|
|
27
27
|
__exportStar(require("./storage"), exports);
|
|
28
28
|
__exportStar(require("./testing"), exports);
|
|
29
|
+
__exportStar(require("./uid"), exports);
|
|
29
30
|
__exportStar(require("./worker-thread"), exports);
|
|
30
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AAEvB,yCAAuB;AACvB,2CAAyB;AACzB,wCAAsB;AACtB,0CAAwB;AACxB,2CAAyB;AACzB,4CAA0B;AAC1B,0CAAwB;AACxB,0CAAwB;AACxB,8CAA4B;AAC5B,4CAA0B;AAC1B,4CAA0B;AAC1B,kDAAgC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AAEvB,yCAAuB;AACvB,2CAAyB;AACzB,wCAAsB;AACtB,0CAAwB;AACxB,2CAAyB;AACzB,4CAA0B;AAC1B,0CAAwB;AACxB,0CAAwB;AACxB,8CAA4B;AAC5B,4CAA0B;AAC1B,4CAA0B;AAC1B,wCAAsB;AACtB,kDAAgC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { BaseHelper } from '../base';
|
|
2
|
+
/**
|
|
3
|
+
* Snowflake ID Configuration Constants (48-10-12)
|
|
4
|
+
* - 48 bits: timestamp (~8,919 years from epoch)
|
|
5
|
+
* - 10 bits: worker ID (1024 workers max)
|
|
6
|
+
* - 12 bits: sequence (4096 per ms per worker)
|
|
7
|
+
*/
|
|
8
|
+
export declare class SnowflakeConfig {
|
|
9
|
+
static readonly DEFAULT_EPOCH: bigint;
|
|
10
|
+
static readonly TIMESTAMP_BITS: bigint;
|
|
11
|
+
static readonly WORKER_ID_BITS: bigint;
|
|
12
|
+
static readonly SEQUENCE_BITS: bigint;
|
|
13
|
+
static readonly MAX_WORKER_ID: bigint;
|
|
14
|
+
static readonly MAX_SEQUENCE: bigint;
|
|
15
|
+
static readonly WORKER_ID_SHIFT: bigint;
|
|
16
|
+
static readonly TIMESTAMP_SHIFT: bigint;
|
|
17
|
+
static readonly MAX_CLOCK_BACKWARD_MS: bigint;
|
|
18
|
+
static readonly MAX_TIMESTAMP_MS: bigint;
|
|
19
|
+
static readonly WARNING_THRESHOLD_MS: bigint;
|
|
20
|
+
}
|
|
21
|
+
export interface IIdGeneratorOptions {
|
|
22
|
+
workerId?: number;
|
|
23
|
+
epoch?: bigint;
|
|
24
|
+
}
|
|
25
|
+
export interface ISnowflakeParsedId {
|
|
26
|
+
raw: bigint;
|
|
27
|
+
timestamp: Date;
|
|
28
|
+
workerId: number;
|
|
29
|
+
sequence: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Snowflake ID Generator with Base62 Encoding
|
|
33
|
+
*
|
|
34
|
+
* Generates unique, time-sortable IDs suitable for distributed systems.
|
|
35
|
+
* Output is Base62 encoded to fit within 15 characters limit.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Initialize with defaults (workerId: 199, epoch: 2025-01-01 00:00:00 UTC)
|
|
40
|
+
* const generator = new SnowflakeUidHelper();
|
|
41
|
+
*
|
|
42
|
+
* // Or with custom values
|
|
43
|
+
* const customGenerator = new SnowflakeUidHelper({
|
|
44
|
+
* workerId: 123,
|
|
45
|
+
* epoch: BigInt(1735689600000),
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* // Generate transaction number
|
|
49
|
+
* const txnNumber = generator.nextId(); // e.g., "9du1sJXO88"
|
|
50
|
+
*
|
|
51
|
+
* // Generate raw snowflake (bigint)
|
|
52
|
+
* const snowflakeId = generator.nextSnowflake(); // e.g., 130546360012247045n
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @description
|
|
56
|
+
* Snowflake ID Structure (70 bits):
|
|
57
|
+
* - 48 bits: timestamp in ms since epoch (2025-01-01) - ~8,919 years
|
|
58
|
+
* - 10 bits: worker ID - 1024 unique workers
|
|
59
|
+
* - 12 bits: sequence number - 4096 IDs per ms per worker
|
|
60
|
+
*
|
|
61
|
+
* Base62 Output: 10-12 chars (max 12 chars, within 15-char limit)
|
|
62
|
+
* Throughput: 4,096,000 IDs/second/worker
|
|
63
|
+
* Max workers: 1024
|
|
64
|
+
* Lifespan: Until ~10,944 AD
|
|
65
|
+
*/
|
|
66
|
+
export declare class SnowflakeUidHelper extends BaseHelper {
|
|
67
|
+
private readonly workerId;
|
|
68
|
+
private readonly epoch;
|
|
69
|
+
private sequence;
|
|
70
|
+
private lastTimestamp;
|
|
71
|
+
constructor(opts?: IIdGeneratorOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Generate next unique ID as Base62 string
|
|
74
|
+
* @returns Base62 encoded ID (max 12 chars, fits 15 char limit)
|
|
75
|
+
*/
|
|
76
|
+
nextId(): string;
|
|
77
|
+
/**
|
|
78
|
+
* Generate next unique ID as raw Snowflake bigint
|
|
79
|
+
* @returns 70-bit Snowflake ID
|
|
80
|
+
*/
|
|
81
|
+
nextSnowflake(): bigint;
|
|
82
|
+
/**
|
|
83
|
+
* Encode a bigint to Base62 string
|
|
84
|
+
*/
|
|
85
|
+
encodeBase62(num: bigint): string;
|
|
86
|
+
/**
|
|
87
|
+
* Decode a Base62 string to bigint
|
|
88
|
+
*/
|
|
89
|
+
decodeBase62(str: string): bigint;
|
|
90
|
+
/**
|
|
91
|
+
* Extract timestamp from a Snowflake ID
|
|
92
|
+
* @returns Date when the ID was generated
|
|
93
|
+
*/
|
|
94
|
+
extractTimestamp(id: bigint): Date;
|
|
95
|
+
/**
|
|
96
|
+
* Extract worker ID from a Snowflake ID
|
|
97
|
+
*/
|
|
98
|
+
extractWorkerId(id: bigint): number;
|
|
99
|
+
/**
|
|
100
|
+
* Extract sequence from a Snowflake ID
|
|
101
|
+
*/
|
|
102
|
+
extractSequence(id: bigint): number;
|
|
103
|
+
/**
|
|
104
|
+
* Parse a Base62 ID and extract its components
|
|
105
|
+
*/
|
|
106
|
+
parseId(base62Id: string): ISnowflakeParsedId;
|
|
107
|
+
/**
|
|
108
|
+
* Get current worker ID
|
|
109
|
+
*/
|
|
110
|
+
getWorkerId(): number;
|
|
111
|
+
private currentTimestamp;
|
|
112
|
+
private waitForNextMs;
|
|
113
|
+
private validateWorkerId;
|
|
114
|
+
private validateEpoch;
|
|
115
|
+
private checkExpiryWarning;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../../src/helpers/uid/helper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKrC;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAyB;IACtD,MAAM,CAAC,QAAQ,CAAC,cAAc,SAAc;IAC5C,MAAM,CAAC,QAAQ,CAAC,cAAc,SAAc;IAC5C,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAc;IAC3C,MAAM,CAAC,QAAQ,CAAC,aAAa,SAAyC;IACtE,MAAM,CAAC,QAAQ,CAAC,YAAY,SAAyC;IACrE,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAc;IAC7C,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAc;IAC7C,MAAM,CAAC,QAAQ,CAAC,qBAAqB,SAAe;IAGpD,MAAM,CAAC,QAAQ,CAAC,gBAAgB,SAAyC;IACzE,MAAM,CAAC,QAAQ,CAAC,oBAAoB,SAA2D;CAChG;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,kBAAmB,SAAQ,UAAU;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAAsB;gBAE/B,IAAI,CAAC,EAAE,mBAAmB;IAoBtC;;;OAGG;IACH,MAAM,IAAI,MAAM;IAKhB;;;OAGG;IACH,aAAa,IAAI,MAAM;IA8CvB;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAkBjC;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAkBjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKlC;;OAEG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAMnC;;OAEG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAInC;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAU7C;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,kBAAkB;CAiB3B"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SnowflakeUidHelper = exports.SnowflakeConfig = void 0;
|
|
4
|
+
const constants_1 = require("../../common/constants");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const app_error_1 = require("../error/app-error");
|
|
7
|
+
const BASE62_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
8
|
+
/**
|
|
9
|
+
* Snowflake ID Configuration Constants (48-10-12)
|
|
10
|
+
* - 48 bits: timestamp (~8,919 years from epoch)
|
|
11
|
+
* - 10 bits: worker ID (1024 workers max)
|
|
12
|
+
* - 12 bits: sequence (4096 per ms per worker)
|
|
13
|
+
*/
|
|
14
|
+
class SnowflakeConfig {
|
|
15
|
+
static { this.DEFAULT_EPOCH = BigInt(1735689600000); } // 2025-01-01 00:00:00 UTC
|
|
16
|
+
static { this.TIMESTAMP_BITS = BigInt(48); }
|
|
17
|
+
static { this.WORKER_ID_BITS = BigInt(10); }
|
|
18
|
+
static { this.SEQUENCE_BITS = BigInt(12); }
|
|
19
|
+
static { this.MAX_WORKER_ID = (BigInt(1) << BigInt(10)) - BigInt(1); } // 1023
|
|
20
|
+
static { this.MAX_SEQUENCE = (BigInt(1) << BigInt(12)) - BigInt(1); } // 4095
|
|
21
|
+
static { this.WORKER_ID_SHIFT = BigInt(12); }
|
|
22
|
+
static { this.TIMESTAMP_SHIFT = BigInt(22); } // 10 + 12
|
|
23
|
+
static { this.MAX_CLOCK_BACKWARD_MS = BigInt(100); }
|
|
24
|
+
// 48 bits max = ~8,919 years, warn 10 years before expiry (~8,909 years)
|
|
25
|
+
static { this.MAX_TIMESTAMP_MS = (BigInt(1) << BigInt(48)) - BigInt(1); }
|
|
26
|
+
static { this.WARNING_THRESHOLD_MS = BigInt(Math.floor(8909 * 365.25 * 24 * 60 * 60 * 1000)); } // ~8,909 years
|
|
27
|
+
}
|
|
28
|
+
exports.SnowflakeConfig = SnowflakeConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Snowflake ID Generator with Base62 Encoding
|
|
31
|
+
*
|
|
32
|
+
* Generates unique, time-sortable IDs suitable for distributed systems.
|
|
33
|
+
* Output is Base62 encoded to fit within 15 characters limit.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // Initialize with defaults (workerId: 199, epoch: 2025-01-01 00:00:00 UTC)
|
|
38
|
+
* const generator = new SnowflakeUidHelper();
|
|
39
|
+
*
|
|
40
|
+
* // Or with custom values
|
|
41
|
+
* const customGenerator = new SnowflakeUidHelper({
|
|
42
|
+
* workerId: 123,
|
|
43
|
+
* epoch: BigInt(1735689600000),
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Generate transaction number
|
|
47
|
+
* const txnNumber = generator.nextId(); // e.g., "9du1sJXO88"
|
|
48
|
+
*
|
|
49
|
+
* // Generate raw snowflake (bigint)
|
|
50
|
+
* const snowflakeId = generator.nextSnowflake(); // e.g., 130546360012247045n
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @description
|
|
54
|
+
* Snowflake ID Structure (70 bits):
|
|
55
|
+
* - 48 bits: timestamp in ms since epoch (2025-01-01) - ~8,919 years
|
|
56
|
+
* - 10 bits: worker ID - 1024 unique workers
|
|
57
|
+
* - 12 bits: sequence number - 4096 IDs per ms per worker
|
|
58
|
+
*
|
|
59
|
+
* Base62 Output: 10-12 chars (max 12 chars, within 15-char limit)
|
|
60
|
+
* Throughput: 4,096,000 IDs/second/worker
|
|
61
|
+
* Max workers: 1024
|
|
62
|
+
* Lifespan: Until ~10,944 AD
|
|
63
|
+
*/
|
|
64
|
+
class SnowflakeUidHelper extends base_1.BaseHelper {
|
|
65
|
+
constructor(opts) {
|
|
66
|
+
super({ scope: SnowflakeUidHelper.name });
|
|
67
|
+
this.sequence = BigInt(0);
|
|
68
|
+
this.lastTimestamp = BigInt(-1);
|
|
69
|
+
const workerId = opts?.workerId ?? 199;
|
|
70
|
+
const epoch = opts?.epoch ?? SnowflakeConfig.DEFAULT_EPOCH;
|
|
71
|
+
this.validateWorkerId(workerId);
|
|
72
|
+
this.workerId = BigInt(workerId);
|
|
73
|
+
this.validateEpoch(epoch);
|
|
74
|
+
this.epoch = epoch;
|
|
75
|
+
this.logger.info('[constructor] Initialized | workerId: %d | epoch: %s | epochDate: %s', workerId, epoch.toString(), new Date(Number(epoch)).toISOString());
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Generate next unique ID as Base62 string
|
|
79
|
+
* @returns Base62 encoded ID (max 12 chars, fits 15 char limit)
|
|
80
|
+
*/
|
|
81
|
+
nextId() {
|
|
82
|
+
const snowflake = this.nextSnowflake();
|
|
83
|
+
return this.encodeBase62(snowflake);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generate next unique ID as raw Snowflake bigint
|
|
87
|
+
* @returns 70-bit Snowflake ID
|
|
88
|
+
*/
|
|
89
|
+
nextSnowflake() {
|
|
90
|
+
let timestamp = this.currentTimestamp();
|
|
91
|
+
// Handle clock going backward
|
|
92
|
+
if (timestamp < this.lastTimestamp) {
|
|
93
|
+
const diff = this.lastTimestamp - timestamp;
|
|
94
|
+
this.logger.warn('[nextSnowflake] Clock moved backward | diff: %d ms', Number(diff));
|
|
95
|
+
// Wait for clock to catch up (max 100ms)
|
|
96
|
+
if (diff <= SnowflakeConfig.MAX_CLOCK_BACKWARD_MS) {
|
|
97
|
+
timestamp = this.waitForNextMs(this.lastTimestamp);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw (0, app_error_1.getError)({
|
|
101
|
+
statusCode: constants_1.HTTP.ResultCodes.RS_5.InternalServerError,
|
|
102
|
+
message: `[IdGenerator][nextSnowflake] Clock moved backward by ${diff}ms. Refusing to generate ID.`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Same millisecond - increment sequence
|
|
107
|
+
if (timestamp === this.lastTimestamp) {
|
|
108
|
+
this.sequence = (this.sequence + BigInt(1)) & SnowflakeConfig.MAX_SEQUENCE;
|
|
109
|
+
// Sequence exhausted for this millisecond
|
|
110
|
+
if (this.sequence === BigInt(0)) {
|
|
111
|
+
timestamp = this.waitForNextMs(timestamp);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// New millisecond - reset sequence
|
|
116
|
+
this.sequence = BigInt(0);
|
|
117
|
+
}
|
|
118
|
+
this.lastTimestamp = timestamp;
|
|
119
|
+
// Check for approaching sequence expiry (10 years before end)
|
|
120
|
+
this.checkExpiryWarning(timestamp);
|
|
121
|
+
// Compose the 70-bit ID
|
|
122
|
+
const id = ((timestamp - this.epoch) << SnowflakeConfig.TIMESTAMP_SHIFT) |
|
|
123
|
+
(this.workerId << SnowflakeConfig.WORKER_ID_SHIFT) |
|
|
124
|
+
this.sequence;
|
|
125
|
+
return id;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Encode a bigint to Base62 string
|
|
129
|
+
*/
|
|
130
|
+
encodeBase62(num) {
|
|
131
|
+
if (num === BigInt(0)) {
|
|
132
|
+
return BASE62_CHARS[0];
|
|
133
|
+
}
|
|
134
|
+
let result = '';
|
|
135
|
+
let value = num;
|
|
136
|
+
const base = BigInt(BASE62_CHARS.length);
|
|
137
|
+
while (value > BigInt(0)) {
|
|
138
|
+
const remainder = value % base;
|
|
139
|
+
result = BASE62_CHARS[Number(remainder)] + result;
|
|
140
|
+
value = value / base;
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Decode a Base62 string to bigint
|
|
146
|
+
*/
|
|
147
|
+
decodeBase62(str) {
|
|
148
|
+
let result = BigInt(0);
|
|
149
|
+
const base = BigInt(BASE62_CHARS.length);
|
|
150
|
+
for (const char of str) {
|
|
151
|
+
const index = BASE62_CHARS.indexOf(char);
|
|
152
|
+
if (index === -1) {
|
|
153
|
+
throw (0, app_error_1.getError)({
|
|
154
|
+
statusCode: constants_1.HTTP.ResultCodes.RS_4.BadRequest,
|
|
155
|
+
message: `[IdGenerator][decodeBase62] Invalid Base62 character: ${char}`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
result = result * base + BigInt(index);
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Extract timestamp from a Snowflake ID
|
|
164
|
+
* @returns Date when the ID was generated
|
|
165
|
+
*/
|
|
166
|
+
extractTimestamp(id) {
|
|
167
|
+
const timestamp = (id >> SnowflakeConfig.TIMESTAMP_SHIFT) + this.epoch;
|
|
168
|
+
return new Date(Number(timestamp));
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Extract worker ID from a Snowflake ID
|
|
172
|
+
*/
|
|
173
|
+
extractWorkerId(id) {
|
|
174
|
+
const extractedWorkerId = (id >> SnowflakeConfig.WORKER_ID_SHIFT) & SnowflakeConfig.MAX_WORKER_ID;
|
|
175
|
+
return Number(extractedWorkerId);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Extract sequence from a Snowflake ID
|
|
179
|
+
*/
|
|
180
|
+
extractSequence(id) {
|
|
181
|
+
return Number(id & SnowflakeConfig.MAX_SEQUENCE);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Parse a Base62 ID and extract its components
|
|
185
|
+
*/
|
|
186
|
+
parseId(base62Id) {
|
|
187
|
+
const raw = this.decodeBase62(base62Id);
|
|
188
|
+
return {
|
|
189
|
+
raw,
|
|
190
|
+
timestamp: this.extractTimestamp(raw),
|
|
191
|
+
workerId: this.extractWorkerId(raw),
|
|
192
|
+
sequence: this.extractSequence(raw),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get current worker ID
|
|
197
|
+
*/
|
|
198
|
+
getWorkerId() {
|
|
199
|
+
return Number(this.workerId);
|
|
200
|
+
}
|
|
201
|
+
currentTimestamp() {
|
|
202
|
+
return BigInt(Date.now());
|
|
203
|
+
}
|
|
204
|
+
waitForNextMs(lastTimestamp) {
|
|
205
|
+
let timestamp = this.currentTimestamp();
|
|
206
|
+
while (timestamp <= lastTimestamp) {
|
|
207
|
+
timestamp = this.currentTimestamp();
|
|
208
|
+
}
|
|
209
|
+
return timestamp;
|
|
210
|
+
}
|
|
211
|
+
validateWorkerId(workerId) {
|
|
212
|
+
if (workerId < 0 || workerId > Number(SnowflakeConfig.MAX_WORKER_ID)) {
|
|
213
|
+
throw (0, app_error_1.getError)({
|
|
214
|
+
statusCode: constants_1.HTTP.ResultCodes.RS_5.InternalServerError,
|
|
215
|
+
message: `[IdGenerator][validateWorkerId] Worker ID must be between 0 and ${SnowflakeConfig.MAX_WORKER_ID} | received: ${workerId}`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
validateEpoch(epoch) {
|
|
220
|
+
const now = BigInt(Date.now());
|
|
221
|
+
if (epoch <= BigInt(0)) {
|
|
222
|
+
throw (0, app_error_1.getError)({
|
|
223
|
+
statusCode: constants_1.HTTP.ResultCodes.RS_5.InternalServerError,
|
|
224
|
+
message: `[IdGenerator][validateEpoch] Epoch must be a positive number | received: ${epoch}`,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (epoch > now) {
|
|
228
|
+
throw (0, app_error_1.getError)({
|
|
229
|
+
statusCode: constants_1.HTTP.ResultCodes.RS_5.InternalServerError,
|
|
230
|
+
message: `[IdGenerator][validateEpoch] Epoch cannot be in the future | received: ${epoch} (${new Date(Number(epoch)).toISOString()}) | now: ${now}`,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
checkExpiryWarning(timestamp) {
|
|
235
|
+
const elapsedMs = timestamp - this.epoch;
|
|
236
|
+
if (elapsedMs < SnowflakeConfig.WARNING_THRESHOLD_MS) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const remainingMs = SnowflakeConfig.MAX_TIMESTAMP_MS - elapsedMs;
|
|
240
|
+
const remainingYears = Number(remainingMs) / (365.25 * 24 * 60 * 60 * 1000);
|
|
241
|
+
const expiryDate = new Date(Number(this.epoch + SnowflakeConfig.MAX_TIMESTAMP_MS));
|
|
242
|
+
this.logger.warn('[checkExpiryWarning] Snowflake ID sequence approaching expiry | remainingYears: %.2f | expiryDate: %s | action: Plan migration to new epoch', remainingYears, expiryDate.toISOString());
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.SnowflakeUidHelper = SnowflakeUidHelper;
|
|
246
|
+
//# sourceMappingURL=helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.js","sourceRoot":"","sources":["../../../src/helpers/uid/helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/helpers/uid/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./helper"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/helpers/uid/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB"}
|