@eliware/snowflake 13.0.0 → 15.0.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/AGENTS.md CHANGED
@@ -2,15 +2,20 @@
2
2
 
3
3
  ## Project
4
4
 
5
- Build a Snowflake ID library with Node.js 26.
6
- Use native ESM.
5
+ Maintain `@eliware/snowflake`, a Snowflake ID library owned by Eliware.
7
6
 
8
7
  ## Scope and boundaries
9
8
 
9
+ Limit this package to Snowflake ID generation.
10
+
10
11
  ## Layout
11
12
 
13
+ Use `README.md` and `specs/README.md` to find repository paths.
14
+
12
15
  ## Development
13
16
 
17
+ Use Node.js 26 and native ESM for maintained JavaScript.
18
+
14
19
  ## Validation
15
20
 
16
21
  Run `npm test`.
@@ -21,8 +26,12 @@ Run `npm run format:check`.
21
26
 
22
27
  ## Security
23
28
 
29
+ Keep credentials, private data, and runtime state out of Git.
30
+
24
31
  ## Changes
25
32
 
33
+ Update the nearest index when you add a document.
34
+
26
35
  ## Library
27
36
 
28
37
  Run focused tests first during development.
@@ -32,3 +41,6 @@ Prevent repeated full-suite runs during development.
32
41
  Run the full `npm test` suite for final validation before a commit, milestone, or release.
33
42
 
34
43
  ## npm publication
44
+
45
+ Run `npm run pack` to check package contents.
46
+ Follow the approved release procedure.
package/README.md CHANGED
@@ -23,14 +23,13 @@ A Node.js Snowflake ID generator with BigInt support and a configurable epoch.
23
23
 
24
24
  ## Features
25
25
 
26
- Create time-ordered Snowflake IDs with a custom epoch and worker and process IDs.
27
- Return decimal strings so JavaScript and JSON preserve each ID exactly.
28
- The generator keeps IDs ordered when time decreases and reports sequence overflow.
26
+ Create time-ordered Snowflake IDs as decimal strings.
27
+ Set a custom epoch, worker ID, process ID, clock, or logger.
29
28
 
30
29
  ## Requirements
31
30
 
32
31
  Use Node.js 26 or later.
33
- Use one package instance in each Node.js process.
32
+ Use native ECMAScript modules (ESM).
34
33
 
35
34
  ## Setup
36
35
 
@@ -42,7 +41,7 @@ npm install @eliware/snowflake
42
41
 
43
42
  ## Usage
44
43
 
45
- Import the generator factory and set a unique worker and process ID pair:
44
+ Create a generator with a unique worker and process ID pair:
46
45
 
47
46
  ```js
48
47
  import { createSnowflakeGenerator } from "@eliware/snowflake";
@@ -52,48 +51,53 @@ console.log(generate());
52
51
  ```
53
52
 
54
53
  Each call returns one decimal string.
55
-
56
- [Release notes](RELEASE_NOTES.md)
57
-
58
- [Specifications](specs/README.md)
54
+ Read the [usage guide](docs/usage.md) for generator options and ID fields.
55
+ Read the [release notes](RELEASE_NOTES.md) for changes by version.
56
+ Read the [specifications index](specs/README.md) for repository requirements.
59
57
 
60
58
  ## Development
61
59
 
62
- [Documentation](docs/README.md)
63
- See the [usage guide](docs/usage.md) for generator options and ID fields.
60
+ Read the [documentation index](docs/README.md) for maintained guides.
64
61
 
65
62
  ## Testing
66
63
 
67
- Run `npm test` from a repository clone to run aggregate validation.
64
+ Run `npm test` from a repository clone for aggregate validation.
68
65
 
69
66
  ## Troubleshooting
70
67
 
71
- Check the options and clock when the generator throws `RangeError`.
72
- For sequence overflow, retry when the clock returns a timestamp greater than the last timestamp.
73
68
  Read the [troubleshooting guide](docs/troubleshooting.md) for error causes and actions.
74
69
 
75
70
  ## Security
76
71
 
77
- Use IDs as identifiers. Each ID contains its generation time and worker and process values.
72
+ Each ID contains its generation time and identity fields.
78
73
  Do not use IDs as secrets or authentication tokens.
79
- Read the [usage guide](docs/usage.md) for ID fields and storage guidance.
80
74
 
81
75
  ## API
82
76
 
83
77
  Import `createSnowflakeGenerator` to create a generator with custom options.
84
- Use `generate`, `snowflake`, or the default export for the default generator.
85
- Read the [usage guide](docs/usage.md) for the API and option details.
78
+ Import `generate`, `snowflake`, or the default export to use the default generator.
79
+ Import `constants` to read the default epoch and field sizes.
80
+ Read the [usage guide](docs/usage.md) for API details and TypeScript declarations.
86
81
 
87
82
  ## Packaging
88
83
 
89
- The package uses native ESM and includes TypeScript declarations.
90
- The package has no runtime dependencies.
91
- Install it from [npm](https://www.npmjs.com/package/@eliware/snowflake).
84
+ The package uses native ESM, includes TypeScript declarations, and depends on `@eliware/log`.
85
+ Its root entrypoint is `src/index.mjs` and its declaration file is `src/index.d.ts`.
86
+ The npm package includes these paths from `package.json`:
87
+
88
+ - `src/`
89
+ - `docs/`
90
+ - `README.md`, `AGENTS.md`, `LICENSE`, and `RELEASE_NOTES.md`
91
+ - `examples/` and `specs/`
92
+
93
+ Use numeric `MAJOR.MINOR.PATCH` versions.
94
+ Push a matching `v<version>` tag to start validation and npm publication.
95
+ Follow the approved release procedure before you create a release tag.
92
96
 
93
97
  ## Examples
94
98
 
95
- [Run the native ESM example](examples/example.mjs).
96
- [Examples](examples/README.md)
99
+ Run `node examples/example.mjs` to create sample IDs.
100
+ Read [examples/README.md](examples/README.md) for the example index.
97
101
 
98
102
  ## Support
99
103
 
package/RELEASE_NOTES.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Release Notes
2
2
 
3
+ ## 15.0.0 — 2026-10-21
4
+
5
+ ### Changed
6
+
7
+ - Updated the package to version 15.0.0 and aligned its specifications with Eliware Test 15.
8
+ - Updated `@eliware/log` and `@eliware/test` to version 15.0.0.
9
+ - Refreshed the lockfile with current transitive dependency versions.
10
+
11
+ ## 14.0.0 — 2026-10-21
12
+
13
+ ### Added
14
+
15
+ - Added optional structured logging through `@eliware/log` with a custom logger option.
16
+ - Added tests for logger records and the full elapsed timestamp range with the maximum epoch.
17
+
18
+ ### Changed
19
+
20
+ - Updated the package to version 14.0.0 and aligned its specifications with Eliware Test 14.
21
+ - Clarified the authoritative rule for first timestamps and later pre-epoch rollbacks.
22
+ - Updated npm dependencies and added `@eliware/log` as a direct dependency.
23
+ - Expanded the user guides with logging, API, decoding, timestamp limits, identity, and storage details.
24
+ - Reduced `README.md` and `AGENTS.md` to convention-required content.
25
+
26
+ ### Fixed
27
+
28
+ - Kept the full elapsed timestamp range available when the configured epoch is at its maximum.
29
+ - Kept IDs increasing when the clock returns a time before the epoch after the first valid ID.
30
+
3
31
  ## 13.0.0 — 2026-10-19
4
32
 
5
33
  ### Added
package/docs/README.md CHANGED
@@ -1,4 +1,13 @@
1
1
  # Documentation
2
2
 
3
- - [Usage](usage.md)
4
- - [Troubleshooting](troubleshooting.md)
3
+ Use these guides to install the package, create IDs, and resolve common errors.
4
+
5
+ ## Guides
6
+
7
+ - [Usage](usage.md) explains installation, generator options, ID fields, decoding, logging, and storage.
8
+ - [Troubleshooting](troubleshooting.md) explains validation errors, sequence limits, and duplicate IDs.
9
+
10
+ ## Requirements
11
+
12
+ Use Node.js 26 or later.
13
+ Use native ECMAScript modules (ESM).
@@ -2,16 +2,17 @@
2
2
 
3
3
  ## Error reference
4
4
 
5
- | Error | Cause | Action |
6
- | --------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------- |
7
- | `RangeError` for `workerId` or `processId` | The value is outside `0` through `31`. | Set an integer from `0` through `31`. |
8
- | `TypeError` for `now` | The option is not a function. | Pass a function that returns Unix time in milliseconds. |
9
- | `RangeError` for `epoch` | The epoch is outside the supported range. | Set the epoch from zero through the timestamp limit. |
10
- | `RangeError` for invalid clock number | The clock returned a fractional or unsafe number. | Return a safe integer number or a bigint. |
11
- | `RangeError` for time before epoch | The clock value is lower than `epoch`. | Set the correct epoch or set the clock source. |
12
- | `RangeError` for timestamp capacity | Elapsed time is greater than the 42-bit limit. | Use a valid epoch for the required date range. |
13
- | `RangeError` for sequence overflow | The generator created 4096 IDs at one timestamp. | Retry when the clock returns a greater timestamp. |
14
- | `TypeError` or `RangeError` during conversion | An option or clock value cannot convert to `BigInt`. | Pass an integer number or bigint value. |
5
+ | Error | Cause | Action |
6
+ | --------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------- |
7
+ | `RangeError` for `workerId` or `processId` | The value is outside `0` through `31`. | Set an integer from `0` through `31`. |
8
+ | `TypeError` for `now` | The option is not a function. | Pass a function that returns Unix time in milliseconds. |
9
+ | `TypeError` for `logger` | The logger lacks a required level method. | Pass a logger with `error`, `warn`, `info`, and `debug` methods. |
10
+ | `RangeError` for `epoch` | The epoch is outside the supported range. | Set the epoch from zero through the timestamp limit. |
11
+ | `RangeError` for invalid clock number | The clock returned a fractional or unsafe number. | Return a safe integer number or a bigint. |
12
+ | `RangeError` for first time before epoch | The first clock value is lower than `epoch`. | Set the correct epoch or set the clock source. |
13
+ | `RangeError` for timestamp capacity | Elapsed time is greater than the 42-bit limit. | Use a valid epoch for the required date range. |
14
+ | `RangeError` for sequence overflow | The generator created 4096 IDs at one timestamp. | Retry when the clock returns a greater timestamp. |
15
+ | `TypeError` or `RangeError` during conversion | An option or clock value cannot convert to `BigInt`. | Pass an integer number or bigint value. |
15
16
 
16
17
  ## Sequence overflow
17
18
 
@@ -28,11 +29,23 @@ The default worker ID is `0`.
28
29
  The default process ID is `process.pid % 32` and can repeat across hosts.
29
30
  Set both IDs in deployment configuration when some hosts create IDs.
30
31
 
32
+ Do not create multiple generators with the same pair while their IDs can overlap in time.
33
+ Each generator starts its sequence at zero.
34
+ Use one generator instance for each pair in a process.
35
+
36
+ ## Clock rollback
37
+
38
+ The generator keeps IDs in increasing order when its clock returns an earlier time.
39
+ It uses the last valid timestamp and advances the sequence.
40
+ It logs a warning when you provide a logger.
41
+ The first clock value must be at or after the configured epoch.
42
+ After the first ID, a clock value lower than the epoch uses rollback handling.
43
+
31
44
  ## Invalid timestamps
32
45
 
33
46
  The clock must return a safe integer number or a bigint.
34
47
  The value must be Unix time in milliseconds.
35
- The timestamp must be at or after the configured epoch.
48
+ The first timestamp must be at or after the configured epoch.
36
49
  The elapsed time must be 42 bits or less.
37
50
  Check the clock and epoch values when timestamp validation fails.
38
51
 
package/docs/usage.md CHANGED
@@ -3,7 +3,8 @@
3
3
  ## Requirements
4
4
 
5
5
  Use Node.js 26 or later.
6
- Use one package instance in each Node.js process.
6
+ Use native ECMAScript modules (ESM).
7
+ Give each active generator a unique worker and process ID pair.
7
8
 
8
9
  ## Install
9
10
 
@@ -27,6 +28,10 @@ console.log(id);
27
28
 
28
29
  The command prints one decimal string. The value changes on each call.
29
30
 
31
+ The package exports `createSnowflakeGenerator`, `generate`, `snowflake`, `constants`, and a default generator.
32
+ The `generate`, `snowflake`, and default exports use the same generator instance.
33
+ Use `createSnowflakeGenerator()` to set an epoch, identity, clock, or logger.
34
+
30
35
  ## Set generator options
31
36
 
32
37
  Pass an options object to `createSnowflakeGenerator`.
@@ -37,6 +42,7 @@ Pass an options object to `createSnowflakeGenerator`.
37
42
  | `workerId` | number or bigint | `0` | Worker value from `0` through `31`. |
38
43
  | `processId` | number or bigint | `process.pid % 32` | Process value from `0` through `31`. |
39
44
  | `now` | function | `Date.now` | Function that returns Unix time in milliseconds. |
45
+ | `logger` | logger | none | Optional structured logger for generator events. |
40
46
 
41
47
  `createSnowflakeGenerator(options)` returns a function that creates IDs.
42
48
  Each call returns one decimal string.
@@ -46,8 +52,9 @@ Use the same epoch for all generators in one application.
46
52
 
47
53
  Give each active generator a unique pair of `workerId` and `processId` values.
48
54
  Keep each pair unique while IDs from that pair remain in use.
49
- Set `processId` when some hosts or processes use the same `workerId`.
50
- The default process ID can repeat across hosts.
55
+ The fields allow 32 worker values and 32 process values, for 1,024 pairs.
56
+ The default process ID is `process.pid % 32` and can repeat across hosts.
57
+ Set both values in deployment configuration when different hosts can create IDs at the same time.
51
58
 
52
59
  To align timestamp decoding with Discord, set `epoch` to `1420070400000n`.
53
60
  This epoch matches Discord's timestamp epoch.
@@ -68,6 +75,7 @@ The timestamp stores milliseconds since the configured epoch.
68
75
  The sequence starts at zero when the timestamp changes.
69
76
  The default epoch is `365662380000n`, or `1981-08-03T04:53:00Z`.
70
77
  The timestamp field sorts before the worker, process, and sequence fields.
78
+ The complete ID has 64 bits.
71
79
 
72
80
  The generator combines the fields as follows:
73
81
 
@@ -75,7 +83,10 @@ The generator combines the fields as follows:
75
83
  ((time - epoch) << 22) | (workerId << 17) | (processId << 12) | sequence
76
84
  ```
77
85
 
78
- The maximum elapsed timestamp is `(1n << 42n) - 1n` milliseconds.
86
+ The epoch option accepts values through `(1n << 42n) - 1n` milliseconds.
87
+ The timestamp field separately stores a maximum of `(1n << 42n) - 1n` elapsed milliseconds.
88
+ The epoch limit applies to the configured epoch, not the final Unix time.
89
+ The maximum supported Unix time equals the epoch plus the maximum elapsed timestamp.
79
90
  IDs can be greater than JavaScript's safe integer limit.
80
91
 
81
92
  ## Use the default generator
@@ -105,6 +116,18 @@ console.log(timestamp.toISOString());
105
116
 
106
117
  Use the same epoch that the generator used to create the ID.
107
118
 
119
+ Read the worker, process, and sequence fields with bit shifts and masks:
120
+
121
+ ```js
122
+ const value = BigInt(id);
123
+ const workerId = (value >> 17n) & 31n;
124
+ const processId = (value >> 12n) & 31n;
125
+ const sequence = value & 4095n;
126
+ ```
127
+
128
+ The package does not export a decoder.
129
+ Use the same field layout and epoch that the generator used to create the ID.
130
+
108
131
  ## Use a custom clock
109
132
 
110
133
  Pass `now` to set the clock source.
@@ -112,6 +135,35 @@ Return a safe integer number or a bigint from that function.
112
135
  The value must be Unix time in milliseconds.
113
136
  Use this option for deterministic tests or a controlled clock source.
114
137
 
138
+ The first clock value must be at or after the configured epoch.
139
+ After the first ID, an earlier clock value uses the last valid timestamp.
140
+ The generator increments the sequence during that rollback.
141
+
142
+ ## Add structured logging
143
+
144
+ Install `@eliware/log` to create a logger. Pass the logger to the generator with the `logger` option.
145
+ The generator writes records only when you provide a logger.
146
+
147
+ ```js
148
+ import { createLogger } from "@eliware/log";
149
+ import { createSnowflakeGenerator } from "@eliware/snowflake";
150
+
151
+ const logger = createLogger({ level: "debug", format: "json" });
152
+ const generate = createSnowflakeGenerator({ logger });
153
+ const id = generate();
154
+ ```
155
+
156
+ The generator writes `info` when it starts, `debug` when it creates an ID, and `warn` when its clock returns an earlier time.
157
+ It writes `error` when ID generation fails.
158
+ Records do not include generated IDs, credentials, tokens, or error messages.
159
+
160
+ Records include the operation, component, and related timestamp or identity fields.
161
+ The logger supports the `error`, `warn`, `info`, `http`, `verbose`, `debug`, and `silly` levels.
162
+ The generator uses only levels that apply to its operations.
163
+ Set the logger level to control which records it writes.
164
+ The `logger` option requires `error`, `warn`, `info`, and `debug` methods.
165
+ The `LoggerWithConfiguredLevels` TypeScript type describes the supported logger interface.
166
+
115
167
  ## Time and sequence limits
116
168
 
117
169
  The generator uses the last timestamp when the clock returns a lower value.
@@ -131,6 +183,24 @@ JSON cannot encode a `bigint` value without custom code.
131
183
  Use a text field or an unsigned 64-bit field in a database.
132
184
  Use `BigInt(id)` for exact integer math in JavaScript.
133
185
 
186
+ Each ID contains its generation time, worker ID, process ID, and sequence.
187
+ Do not use an ID as a password, credential, or authentication token.
188
+
189
+ ## Use TypeScript
190
+
191
+ The package includes TypeScript declarations for its public API.
192
+ Import `SnowflakeGeneratorOptions`, `SnowflakeConstants`, and `LoggerWithConfiguredLevels` as types.
193
+
194
+ ```ts
195
+ import { createSnowflakeGenerator, constants } from "@eliware/snowflake";
196
+ import type { SnowflakeGeneratorOptions } from "@eliware/snowflake";
197
+
198
+ const options: SnowflakeGeneratorOptions = { workerId: 3, processId: 7 };
199
+ const generate = createSnowflakeGenerator(options);
200
+ const id: string = generate();
201
+ const epoch: bigint = constants.epoch;
202
+ ```
203
+
134
204
  ## Run the example
135
205
 
136
206
  Use Node.js 26 or later.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eliware/snowflake",
3
- "version": "13.0.0",
3
+ "version": "15.0.0",
4
4
  "type": "module",
5
5
  "description": "A Node.js Snowflake ID generator with BigInt support and a configurable epoch.",
6
6
  "keywords": [
@@ -41,8 +41,11 @@
41
41
  "engines": {
42
42
  "node": ">=26"
43
43
  },
44
+ "dependencies": {
45
+ "@eliware/log": "^15.0.0"
46
+ },
44
47
  "devDependencies": {
45
- "@eliware/test": "^13.0.0",
48
+ "@eliware/test": "^15.0.0",
46
49
  "typescript": "^7.0.2"
47
50
  },
48
51
  "jest": {
@@ -1,4 +1,4 @@
1
- version: "13.0"
1
+ version: "15.0"
2
2
  description: Defines behavior and limits for the Snowflake ID generator.
3
3
  directives:
4
4
  - id: E-106.0
@@ -12,8 +12,11 @@ directives:
12
12
  - id: E-106.0.0
13
13
  dos:
14
14
  - Validate worker and process IDs before generation.
15
- - Reject timestamps before the configured epoch.
15
+ - Reject the first clock value when it is before the configured epoch.
16
+ - Apply rollback handling to a later clock value before the configured epoch.
17
+ - Use the last valid timestamp after a rollback.
16
18
  donts:
19
+ - Do not create an ID from a timestamp before the configured epoch.
17
20
  - Do not use identity values outside the supported bit range.
18
21
  - id: E-106.0.1
19
22
  dos:
@@ -1,4 +1,4 @@
1
- version: "13.0"
1
+ version: "15.0"
2
2
  description: Defines work outside the Snowflake ID library scope.
3
3
  directives:
4
4
  - id: E-106.2
@@ -1,4 +1,4 @@
1
- version: "13.0"
1
+ version: "15.0"
2
2
  description: Defines repository requirements for the Snowflake ID library.
3
3
  directives:
4
4
  - id: E-106.1
@@ -8,6 +8,7 @@ export function validateGeneratorOptions({
8
8
  workerId = 0,
9
9
  processId = process.pid % 32,
10
10
  now = defaultNow,
11
+ logger,
11
12
  } = {}) {
12
13
  if (typeof epoch === "number" && !Number.isSafeInteger(epoch))
13
14
  throw new RangeError("epoch must be between 0 and the timestamp limit");
@@ -16,6 +17,12 @@ export function validateGeneratorOptions({
16
17
  throw new RangeError("epoch must be between 0 and the timestamp limit");
17
18
  const identity = validateIdentity(workerId, processId);
18
19
  if (typeof now !== "function") throw new TypeError("clock source must be a function");
20
+ if (
21
+ logger !== undefined &&
22
+ (!logger ||
23
+ ["error", "warn", "info", "debug"].some((level) => typeof logger[level] !== "function"))
24
+ )
25
+ throw new TypeError("logger must provide error, warn, info, and debug methods");
19
26
 
20
- return { baseEpoch, ...identity, now };
27
+ return { baseEpoch, ...identity, now, logger };
21
28
  }
package/src/generator.mjs CHANGED
@@ -8,42 +8,76 @@ import {
8
8
  import { validateGeneratorOptions } from "./generator-options.mjs";
9
9
 
10
10
  export function createGenerator(options = {}) {
11
- const { baseEpoch, worker, processNumber, now } = validateGeneratorOptions(options);
11
+ const { baseEpoch, worker, processNumber, now, logger } = validateGeneratorOptions(options);
12
12
 
13
13
  let lastTimestamp = -1n;
14
14
  let sequence = 0n;
15
15
 
16
+ logger?.info("Snowflake generator created", {
17
+ component: "snowflake",
18
+ operation: "create-generator",
19
+ epoch: baseEpoch.toString(),
20
+ workerId: worker.toString(),
21
+ processId: processNumber.toString(),
22
+ });
23
+
16
24
  function readTime() {
17
25
  const clockValue = now();
18
26
  if (typeof clockValue === "number" && !Number.isSafeInteger(clockValue))
19
27
  throw new RangeError("current time must be a safe integer or bigint");
20
28
  const timestamp = BigInt(clockValue);
21
- if (timestamp < baseEpoch) throw new RangeError("current time must not be before epoch");
29
+ if (timestamp < baseEpoch && lastTimestamp < baseEpoch)
30
+ throw new RangeError("current time must not be before epoch");
22
31
  return timestamp;
23
32
  }
24
33
 
25
34
  return function generate() {
26
- let timestamp = readTime();
27
- if (timestamp < lastTimestamp) timestamp = lastTimestamp;
28
- let nextSequence;
29
- if (timestamp === lastTimestamp) {
30
- if (sequence === SEQUENCE_MASK)
31
- throw new RangeError(
32
- "sequence overflow. Retry when the clock returns a greater timestamp.",
33
- );
34
- nextSequence = sequence + 1n;
35
- } else {
36
- nextSequence = 0n;
35
+ try {
36
+ let timestamp = readTime();
37
+ if (timestamp < lastTimestamp) {
38
+ logger?.warn("Snowflake clock moved backward", {
39
+ component: "snowflake",
40
+ operation: "generate",
41
+ event: "clock-rollback",
42
+ timestamp: timestamp.toString(),
43
+ lastTimestamp: lastTimestamp.toString(),
44
+ });
45
+ timestamp = lastTimestamp;
46
+ }
47
+ let nextSequence;
48
+ if (timestamp === lastTimestamp) {
49
+ if (sequence === SEQUENCE_MASK)
50
+ throw new RangeError(
51
+ "sequence overflow. Retry when the clock returns a greater timestamp.",
52
+ );
53
+ nextSequence = sequence + 1n;
54
+ } else {
55
+ nextSequence = 0n;
56
+ }
57
+ const elapsed = timestamp - baseEpoch;
58
+ if (elapsed > MAX_TIMESTAMP) throw new RangeError("timestamp exceeds Snowflake capacity");
59
+ lastTimestamp = timestamp;
60
+ sequence = nextSequence;
61
+ const id = (
62
+ (elapsed << (WORKER_BITS + PROCESS_BITS + SEQUENCE_BITS)) |
63
+ (worker << (PROCESS_BITS + SEQUENCE_BITS)) |
64
+ (processNumber << SEQUENCE_BITS) |
65
+ nextSequence
66
+ ).toString();
67
+ logger?.debug("Snowflake ID generated", {
68
+ component: "snowflake",
69
+ operation: "generate",
70
+ timestamp: timestamp.toString(),
71
+ sequence: nextSequence.toString(),
72
+ });
73
+ return id;
74
+ } catch (error) {
75
+ logger?.error("Snowflake ID generation failed", {
76
+ component: "snowflake",
77
+ operation: "generate",
78
+ errorType: error.name,
79
+ });
80
+ throw error;
37
81
  }
38
- const elapsed = timestamp - baseEpoch;
39
- if (elapsed > MAX_TIMESTAMP) throw new RangeError("timestamp exceeds Snowflake capacity");
40
- lastTimestamp = timestamp;
41
- sequence = nextSequence;
42
- return (
43
- (elapsed << (WORKER_BITS + PROCESS_BITS + SEQUENCE_BITS)) |
44
- (worker << (PROCESS_BITS + SEQUENCE_BITS)) |
45
- (processNumber << SEQUENCE_BITS) |
46
- nextSequence
47
- ).toString();
48
82
  };
49
83
  }
package/src/index.d.ts CHANGED
@@ -1,10 +1,15 @@
1
+ import type { LoggerWithConfiguredLevels } from "@eliware/log";
2
+
1
3
  export interface SnowflakeGeneratorOptions {
2
4
  epoch?: number | bigint;
3
5
  workerId?: number | bigint;
4
6
  processId?: number | bigint;
5
7
  now?: () => number | bigint;
8
+ logger?: LoggerWithConfiguredLevels;
6
9
  }
7
10
 
11
+ export type { LoggerWithConfiguredLevels } from "@eliware/log";
12
+
8
13
  export interface SnowflakeConstants {
9
14
  readonly epoch: bigint;
10
15
  readonly sequenceBits: bigint;