@eliware/snowflake 1.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Eli Sterling, eliware.org
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # [![eliware.org](https://eliware.org/logos/brand.png)](https://discord.gg/M6aTR9eTwN)
2
+
3
+ ## @eliware/snowflake [![npm version](https://img.shields.io/npm/v/@eliware/snowflake.svg)](https://www.npmjs.com/package/@eliware/snowflake)[![license](https://img.shields.io/github/license/eliware/snowflake.svg)](LICENSE)[![build status](https://github.com/eliware/snowflake/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eliware/snowflake/actions)
4
+
5
+ > A snowflake for Node.js (Insert Brief Description)
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ - [Features](#features)
12
+ - [Installation](#installation)
13
+ - [Usage](#usage)
14
+ - [ESM Example](#esm-example)
15
+ - [CommonJS Example](#commonjs-example)
16
+ - [API](#api)
17
+ - [TypeScript](#typescript)
18
+ - [Testing](#testing)
19
+ - [License](#license)
20
+
21
+ ## Features
22
+
23
+ - Minimal, dependency-light Snowflake ID generator compatible with Discord-style bit layout.
24
+ - BigInt-safe implementation to preserve full 64-bit IDs.
25
+ - Works in both ESM and CommonJS environments.
26
+ - Configurable epoch and worker ID via a factory function.
27
+ - Includes TypeScript declarations and basic tests.
28
+
29
+ ## Installation
30
+
31
+ Install from npm:
32
+
33
+ ```bash
34
+ npm install @eliware/snowflake
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### ESM Example
40
+
41
+ ```js
42
+ // ESM (index.mjs)
43
+ import generate, { createSnowflakeGenerator } from './index.mjs';
44
+
45
+ // default generator (workerId: 0)
46
+ console.log('id:', generate());
47
+
48
+ // create a generator for a specific worker ID
49
+ const gen = createSnowflakeGenerator({ workerId: 1 });
50
+ console.log('worker 1 id:', gen());
51
+ ```
52
+
53
+ ### CommonJS Example
54
+
55
+ ```js
56
+ // CommonJS (index.cjs)
57
+ const generate = require('./index.cjs');
58
+ const { createSnowflakeGenerator } = require('./index.cjs');
59
+
60
+ console.log('id:', generate());
61
+
62
+ const gen = createSnowflakeGenerator({ workerId: 2 });
63
+ console.log('worker 2 id:', gen());
64
+ ```
65
+
66
+ ## API
67
+
68
+ ### createSnowflakeGenerator(options?) => () => string
69
+
70
+ - options.epoch: number | bigint (default: 1420070400000) — base epoch in milliseconds (Discord epoch: 2015-01-01T00:00:00.000Z).
71
+ - options.workerId: number (default: 0) — numeric worker/node ID (10-bit value).
72
+
73
+ Returns a zero-argument function that generates a new Snowflake ID (as a decimal string) each call.
74
+
75
+ Behavior notes:
76
+ - Timestamp uses (Date.now() - epoch) shifted left 22 bits.
77
+ - Worker ID occupies 10 bits, sequence counter occupies 12 bits.
78
+ - The generator waits for the next millisecond if more than 4095 IDs are requested in the same millisecond.
79
+
80
+ ### Default export: generate()
81
+
82
+ A ready-to-use generator (workerId 0). It returns a decimal string representation of the Snowflake ID.
83
+
84
+ ## TypeScript
85
+
86
+ Type definitions are included (index.d.ts). Example signatures:
87
+
88
+ ```ts
89
+ export function createSnowflakeGenerator(options?: { epoch?: number | bigint; workerId?: number }): () => string;
90
+ export const generate: () => string;
91
+ export default generate;
92
+ ```
93
+
94
+ ## Testing
95
+
96
+ A small Jest test suite is included (index.test.mjs / index.test.cjs) that verifies:
97
+
98
+ - Generated IDs are numeric strings parseable to BigInt.
99
+ - Consecutive IDs are monotonically increasing.
100
+ - Worker ID bits are encoded correctly.
101
+ - Timestamp portion decodes to a recent time.
102
+
103
+ Run tests with:
104
+
105
+ ```bash
106
+ npm test
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Support
112
+
113
+ For help, questions, or to chat with the author and community, visit:
114
+
115
+ [![Discord](https://eliware.org/logos/discord_96.png)](https://discord.gg/M6aTR9eTwN)[![eliware.org](https://eliware.org/logos/eliware_96.png)](https://discord.gg/M6aTR9eTwN)
116
+
117
+ **[eliware.org on Discord](https://discord.gg/M6aTR9eTwN)**
118
+
119
+ ## License
120
+
121
+ [MIT © 2025 Eli Sterling, eliware.org](LICENSE)
122
+
123
+ ## Links
124
+
125
+ - [Home Page](https://eliware.org)
126
+ - [GitHub](https://github.com/eliware/snowflake)
127
+ - [npm](https://www.npmjs.com/package/@eliware/snowflake)
128
+ - [Discord](https://discord.gg/M6aTR9eTwN)
package/index.cjs ADDED
@@ -0,0 +1,37 @@
1
+ // Snowflake generator (CommonJS)
2
+ const DEFAULT_EPOCH = 1420070400000n; // Discord epoch: 2015-01-01T00:00:00.000Z
3
+
4
+ function createSnowflakeGenerator({ epoch = DEFAULT_EPOCH, workerId = 0 } = {}) {
5
+ const _epoch = BigInt(epoch);
6
+ const _workerId = BigInt(workerId) & 0x3ffn; // 10 bits
7
+ let lastTimestamp = 0n;
8
+ let sequence = 0n;
9
+
10
+ return function generate() {
11
+ let now = BigInt(Date.now());
12
+
13
+ if (now === lastTimestamp) {
14
+ sequence = (sequence + 1n) & 0xfffn; // 12 bits
15
+ if (sequence === 0n) {
16
+ // Sequence overflow in the same millisecond — wait for next ms
17
+ while (now <= lastTimestamp) {
18
+ now = BigInt(Date.now());
19
+ }
20
+ }
21
+ } else {
22
+ sequence = 0n;
23
+ }
24
+
25
+ lastTimestamp = now;
26
+
27
+ const id = ((now - _epoch) << 22n) | (_workerId << 12n) | sequence;
28
+ return id.toString();
29
+ };
30
+ }
31
+
32
+ // Default generator (workerId 0)
33
+ const generate = createSnowflakeGenerator();
34
+
35
+ module.exports = generate;
36
+ module.exports.generate = generate;
37
+ module.exports.createSnowflakeGenerator = createSnowflakeGenerator;
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function createSnowflakeGenerator(options?: { epoch?: number | bigint; workerId?: number }): () => string;
2
+ export const generate: () => string;
3
+ export default generate;
package/index.mjs ADDED
@@ -0,0 +1,34 @@
1
+ // Snowflake generator (ESM)
2
+ const DEFAULT_EPOCH = 1420070400000n; // Discord epoch: 2015-01-01T00:00:00.000Z
3
+
4
+ export function createSnowflakeGenerator({ epoch = DEFAULT_EPOCH, workerId = 0 } = {}) {
5
+ const _epoch = BigInt(epoch);
6
+ const _workerId = BigInt(workerId) & 0x3ffn; // 10 bits
7
+ let lastTimestamp = 0n;
8
+ let sequence = 0n;
9
+
10
+ return function generate() {
11
+ let now = BigInt(Date.now());
12
+
13
+ if (now === lastTimestamp) {
14
+ sequence = (sequence + 1n) & 0xfffn; // 12 bits
15
+ if (sequence === 0n) {
16
+ // Sequence overflow in the same millisecond — wait for next ms
17
+ while (now <= lastTimestamp) {
18
+ now = BigInt(Date.now());
19
+ }
20
+ }
21
+ } else {
22
+ sequence = 0n;
23
+ }
24
+
25
+ lastTimestamp = now;
26
+
27
+ const id = ((now - _epoch) << 22n) | (_workerId << 12n) | sequence;
28
+ return id.toString();
29
+ };
30
+ }
31
+
32
+ // Default generator (workerId 0)
33
+ export const generate = createSnowflakeGenerator();
34
+ export default generate;
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@eliware/snowflake",
3
+ "type": "module",
4
+ "version": "1.1.1",
5
+ "description": "A minimal Node.js Snowflake ID generator (Discord-compatible). Provides BigInt-safe generators for ESM and CommonJS with configurable epoch and worker ID.",
6
+ "main": "index.cjs",
7
+ "module": "index.mjs",
8
+ "types": "index.d.ts",
9
+ "files": [
10
+ "index.mjs",
11
+ "index.cjs",
12
+ "index.d.ts",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "import": "./index.mjs",
19
+ "require": "./index.cjs",
20
+ "types": "./index.d.ts"
21
+ }
22
+ },
23
+ "scripts": {
24
+ "test": "npx --node-options=\"--experimental-vm-modules --no-warnings\" jest --detectOpenHandles --silent"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/eliware/snowflake.git"
29
+ },
30
+ "keywords": [
31
+ "snowflake",
32
+ "snowflake-id",
33
+ "id-generator",
34
+ "discord",
35
+ "unique-id",
36
+ "bigint",
37
+ "nodejs",
38
+ "esm",
39
+ "cjs"
40
+ ],
41
+ "author": "Eli Sterling, eliware.org <eli@eliware.org>",
42
+ "license": "MIT",
43
+ "bugs": {
44
+ "url": "https://github.com/eliware/snowflake/issues"
45
+ },
46
+ "homepage": "https://github.com/eliware/snowflake#readme",
47
+ "devDependencies": {
48
+ "jest": "^30.0.4"
49
+ },
50
+ "jest": {
51
+ "testEnvironment": "node",
52
+ "testMatch": [
53
+ "**/?(*.)+(spec|test).[jt]s?(x)",
54
+ "**/?(*.)+(spec|test).mjs",
55
+ "**/?(*.)+(spec|test).cjs"
56
+ ]
57
+ },
58
+ "dependencies": {
59
+ "@eliware/common": "^1.1.1"
60
+ }
61
+ }