simpleflakes 4.0.0 → 4.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/README.md CHANGED
@@ -5,19 +5,18 @@
5
5
  [![coveralls status][coveralls-badge]][coveralls-link]
6
6
  [![npm downloads](https://img.shields.io/npm/dm/simpleflakes.svg?style=flat)](https://www.npmjs.com/package/simpleflakes)
7
7
  [![Bundle Size](https://img.shields.io/bundlephobia/minzip/simpleflakes?style=flat)](https://bundlephobia.com/package/simpleflakes)
8
- [![Dependencies](https://badgen.net/bundlephobia/dependency-count/simpleflakes)](https://www.npmjs.com/package/simpleflakes)
9
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
10
9
  [![Node.js](https://img.shields.io/badge/node-%3E%3D16.0.0-brightgreen.svg?style=flat)](https://nodejs.org/)
11
- [![Performance](https://img.shields.io/badge/performance-8.8M%20ops%2Fsec-brightgreen?style=flat&logo=javascript)](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml)
10
+ [![Performance](https://img.shields.io/badge/performance-11.5M%20ops%2Fsec-brightgreen?style=flat&logo=javascript)](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml)
12
11
  [![Last Commit](https://img.shields.io/github/last-commit/leodutra/simpleflakes.svg?style=flat)](https://github.com/leodutra/simpleflakes)
13
- [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes?ref=badge_shield)
12
+ [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes.svg?type=shield&issueType=license)](https://app.fossa.io/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes?ref=badge_shield&issueType=license)
14
13
 
15
- > **Fast, lightweight, and reliable distributed 64-bit ID generation for Node.js**
16
- > Zero dependencies • TypeScript-ready • 8.8M+ ops/sec performance
14
+ > **Fast, lightweight, and reliable distributed 64-bit ID generation for Node.js and the web**
15
+ > Zero dependencies • TypeScript-ready • 10M+ ops/sec performance
17
16
 
18
17
  ## Features
19
18
 
20
- - ⚡ **8.8M+ ops/sec** - Ultra-fast performance
19
+ - ⚡ **10M+ ops/sec** - Ultra-fast performance
21
20
  - 🔢 **Time-oriented 64-bit IDs** - Globally unique, sortable by creation time
22
21
  - 0️⃣ **Zero dependencies** - Pure JavaScript, lightweight bundle
23
22
  - 🏷️ **TypeScript-ready** - Full type safety and universal module support
@@ -49,6 +48,8 @@ Simpleflake generates **unique 64-bit integers** that are:
49
48
 
50
49
  Perfect for database primary keys, distributed system IDs, and anywhere you need fast, unique identifiers.
51
50
 
51
+ Works in Node.js and modern browsers with BigInt and Web Crypto support.
52
+
52
53
  ## References
53
54
 
54
55
  - **[Original Presentation](http://akmanalp.com/simpleflake_presentation/)** - Introduction to the concept by Mali Akmanalp
@@ -156,13 +157,29 @@ This gives you:
156
157
 
157
158
  This library is optimized for speed:
158
159
 
159
- ```javascript
160
- // Benchmark results (operations per second)
161
- simpleflake() // ~8.8M+ ops/sec
162
- parseSimpleflake() // ~3.9M+ ops/sec
163
- binary() // ~26M+ ops/sec
160
+ | Operation | Ops/sec | Time/op |
161
+ |-----------|---------|---------|
162
+ | `simpleflake()` | 11,468,350 | 87.20 ns |
163
+ | `simpleflake(timestamp, randomBits, epoch)` | 14,557,764 | 68.69 ns |
164
+ | `binary()` | 22,794,523 | 43.87 ns |
165
+ | `BigInt()` | 15,933,159 | 62.76 ns |
166
+ | `parseSimpleflake()` | 6,722,882 | 148.75 ns |
167
+
168
+ Benchmark command:
169
+
170
+ ```bash
171
+ npm run benchmark
164
172
  ```
165
173
 
174
+ Benchmark environment:
175
+
176
+ - Node.js v24.14.1
177
+ - Linux 6.6.87.2-microsoft-standard-WSL2 (WSL2)
178
+ - AMD Ryzen 7 5800X3D 8-Core Processor
179
+ - 8 cores / 16 threads
180
+
181
+ Results will vary across CPUs, Node.js versions, power profiles, and native Linux vs. WSL2 environments.
182
+
166
183
  Perfect for high-throughput applications requiring millions of IDs per second.
167
184
 
168
185
  ## Architecture
@@ -182,6 +199,13 @@ No coordination required between multiple ID generators:
182
199
  - **Random collision protection**: 23 random bits provide 8.3M combinations per millisecond
183
200
  - **High availability**: Each service can generate IDs independently
184
201
 
202
+ ### Randomness Considerations
203
+
204
+ - **Cryptographic randomness by default**: simpleflake() uses Web Crypto in browsers and Node's built-in crypto implementation in Node.js.
205
+ - **No Math.random() fallback**: this keeps the default entropy source strong and avoids silently weakening collision resistance.
206
+ - **Runtime requirements**: modern browsers need `crypto.getRandomValues()` and Node.js needs version 16 or newer.
207
+ - **Deterministic or legacy environments**: pass `randomBits` explicitly if you need repeatable output or if you are targeting a runtime without crypto support.
208
+
185
209
  ## Use Cases
186
210
 
187
211
  ### Database Primary Keys
@@ -2,7 +2,7 @@ declare const SIMPLEFLAKE_EPOCH = 946684800000n;
2
2
  /**
3
3
  * Generates a simpleflake ID
4
4
  * @param ts - Timestamp in milliseconds (defaults to current time)
5
- * @param randomBits - Random bits for the ID (defaults to a random value)
5
+ * @param randomBits - Random bits for the ID (defaults to a cryptographically secure random value)
6
6
  * @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)
7
7
  * @returns Generated simpleflake as a BigInt
8
8
  */
@@ -1 +1 @@
1
- {"version":3,"file":"simpleflakes.d.ts","sourceRoot":"","sources":["../src/simpleflakes.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,iBAAiB,gBAAgB,CAAC;AAYxC;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,EAAE,GAAE,MAAM,GAAG,MAAmB,EAChC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAC5B,KAAK,GAAE,MAAM,GAAG,MAA0B,GACzC,MAAM,CAOR;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAC/B,OAAO,GAAE,OAAc,GACtB,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAC9B,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,CAKR;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAOlD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAC9B,iBAAiB,CAWnB;AAGD,OAAO,EAAE,iBAAiB,EAAE,CAAC;;;;;;;;;AAG7B,wBAOE"}
1
+ {"version":3,"file":"simpleflakes.d.ts","sourceRoot":"","sources":["../src/simpleflakes.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,iBAAiB,gBAAgB,CAAC;AA2DxC;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,EAAE,GAAE,MAAM,GAAG,MAAmB,EAChC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAC5B,KAAK,GAAE,MAAM,GAAG,MAA0B,GACzC,MAAM,CAOR;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAC/B,OAAO,GAAE,OAAc,GACtB,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAC9B,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,CAKR;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,SAAwB,SAAS,EAAE,MAAM,CAAC;IAC1C,SAAwB,UAAU,EAAE,MAAM,CAAC;gBAE/B,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAOlD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAC9B,iBAAiB,CAWnB;AAGD,OAAO,EAAE,iBAAiB,EAAE,CAAC;;;;;;;;;AAG7B,wBAOE"}
@@ -1,3 +1,3 @@
1
- "use strict";function _define_property(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}Object.defineProperty(exports,"__esModule",{value:!0}),function(e,t){for(var r in t)Object.defineProperty(e,r,{enumerable:!0,get:Object.getOwnPropertyDescriptor(t,r).get})}(exports,{get SIMPLEFLAKE_EPOCH(){return SIMPLEFLAKE_EPOCH},get SimpleflakeStruct(){return SimpleflakeStruct},get binary(){return binary},get default(){return _default},get extractBits(){return extractBits},get parseSimpleflake(){return parseSimpleflake},get simpleflake(){return simpleflake}});const SIMPLEFLAKE_EPOCH=946684800000n;function simpleflake(e=Date.now(),t,r=SIMPLEFLAKE_EPOCH){return BigInt(e)-BigInt(r)<<23n|BigInt(t??Math.round(8388607*Math.random()))}function binary(e,t=!0){let r=BigInt(e).toString(2);return t&&r.length<64?"0000000000000000000000000000000000000000000000000000000000000000".substr(0,64-r.length)+r:r}function extractBits(e,t,r){let n=BigInt(t),i=BigInt(r);return BigInt(e)>>n&(1n<<i)-1n}class SimpleflakeStruct{constructor(e,t){if(_define_property(this,"timestamp",void 0),_define_property(this,"randomBits",void 0),null==e||null==t)throw Error("Missing argument for SimpleflakeStruct.");this.timestamp=e,this.randomBits=t}}function parseSimpleflake(e){return new SimpleflakeStruct(extractBits(e,23n,41n)+SIMPLEFLAKE_EPOCH,extractBits(e,0n,23n))}const _default={binary,extractBits,parseSimpleflake,SIMPLEFLAKE_EPOCH,simpleflake,SimpleflakeStruct};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),function(e,t){for(var r in t)Object.defineProperty(e,r,{enumerable:!0,get:Object.getOwnPropertyDescriptor(t,r).get})}(exports,{get SIMPLEFLAKE_EPOCH(){return SIMPLEFLAKE_EPOCH},get SimpleflakeStruct(){return SimpleflakeStruct},get binary(){return binary},get default(){return _default},get extractBits(){return extractBits},get parseSimpleflake(){return parseSimpleflake},get simpleflake(){return simpleflake}});const SIMPLEFLAKE_EPOCH=946684800000n;let randomBuffer=new Uint32Array(1024),randomBufferIndex=1024;function toBigInt(e){return"bigint"==typeof e?e:BigInt(e)}function getRandomSource(){let e=globalThis.crypto;if(e)return e;try{return require("node:crypto").webcrypto}catch{throw Error("Cryptographically secure random values are unavailable in this environment.")}}function refillRandomBuffer(){getRandomSource().getRandomValues(randomBuffer),randomBufferIndex=0}function random23(){randomBufferIndex>=1024&&refillRandomBuffer();let e=randomBuffer[randomBufferIndex];return randomBufferIndex+=1,BigInt(8388607&e)}function simpleflake(e=Date.now(),t,r=SIMPLEFLAKE_EPOCH){return toBigInt(e)-toBigInt(r)<<23n|(null==t?random23():toBigInt(t))}function binary(e,t=!0){let r=toBigInt(e).toString(2);return t&&r.length<64?"0000000000000000000000000000000000000000000000000000000000000000".substr(0,64-r.length)+r:r}function extractBits(e,t,r){let n=toBigInt(t),i=toBigInt(r);return toBigInt(e)>>n&(1n<<i)-1n}class SimpleflakeStruct{constructor(e,t){if(null==e||null==t)throw Error("Missing argument for SimpleflakeStruct.");this.timestamp=e,this.randomBits=t}}function parseSimpleflake(e){return new SimpleflakeStruct(extractBits(e,23n,41n)+SIMPLEFLAKE_EPOCH,extractBits(e,0n,23n))}const _default={binary,extractBits,parseSimpleflake,SIMPLEFLAKE_EPOCH,simpleflake,SimpleflakeStruct};
2
2
 
3
3
  //# sourceMappingURL=simpleflakes.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/simpleflakes.ts"],"names":["SIMPLEFLAKE_EPOCH","SimpleflakeStruct","binary","extractBits","parseSimpleflake","simpleflake","ts","Date","now","randomBits","epoch","BigInt","Math","round","random","value","padding","binValue","toString","length","CACHE_64_BIT_ZEROS","substr","data","shift","shiftN","lengthN","timestamp","Error","flake"],"mappings":"8UAuGSA,2BAAAA,uBAlCIC,2BAAAA,uBA/BGC,gBAAAA,YAoEhB,iBAAA,cAnDgBC,qBAAAA,iBAgCAC,0BAAAA,sBApEAC,qBAAAA,eAnBhB,MAAML,kBAAoB,YAAA,AAAa,CAAA,CAmBhC,SAASK,YACdC,EAAsBC,KAAKC,GAAG,EAAE,CAChCC,CAA4B,CAC5BC,EAAyBV,iBAAiB,EAI1C,OACE,AAAEW,OAAOL,GAAMK,OAAOD,IApBU,EAAA,AAAG,CAAA,CAqBnCC,OAAOF,GAAcG,KAAKC,KAAK,CA3BR,AA2BSD,QAAAA,KAAKE,MAAM,IAE/C,CAQO,SAASZ,OACda,CAA+B,CAC/BC,EAAmB,CAAA,CAAI,EAEvB,IAAMC,EAAWN,OAAOI,GAAOG,QAAQ,CAAC,GACxC,OAAOF,GAAWC,EAASE,MAAM,CAAG,GAjCpC,AAkCIC,mEAAmBC,MAAM,CAAC,EAAG,GAAKJ,EAASE,MAAM,EAAIF,EACrDA,CACN,CASO,SAASd,YACdmB,CAA8B,CAC9BC,CAAsB,CACtBJ,CAAuB,EAEvB,IAAMK,EAASb,OAAOY,GAChBE,EAAUd,OAAOQ,GAEvB,OAAO,AAACR,OAAOW,IAASE,EAAW,AAAC,CAAA,CAAA,AAAE,CAAA,EAAIC,CAAM,EAAK,CAAA,AAAE,CAAA,AACzD,CAKO,MAAMxB,kBAIX,YAAYyB,CAAiB,CAAEjB,CAAkB,CAAE,CACjD,GAJF,sBAAgBiB,YAAhB,KAAA,GACA,sBAAgBjB,aAAhB,KAAA,GAGMiB,AAAa,MAAbA,GAAqBjB,AAAc,MAAdA,EACvB,MAAM,AAAIkB,MAAM,0CAElB,CAAA,IAAI,CAACD,SAAS,CAAGA,EACjB,IAAI,CAACjB,UAAU,CAAGA,CACpB,CACF,CAOO,SAASL,iBACdwB,CAA+B,EAE/B,OAAO,IAAI3B,kBAETE,YACEyB,EAtF8B,EAAA,AAAG,CAAA,CAJF,EAAA,AAAG,CAAA,EA6FhC5B,kBAEJG,YAAYyB,EA5FiB,CAAA,AAAE,CAAA,CAFD,EAAA,AAAG,CAAA,EAgGrC,OAMA,SAAe,CACb1B,OACAC,YACAC,iBACAJ,kBACAK,YACAJ,iBACF","file":"simpleflakes.js","sourcesContent":["const SIMPLEFLAKE_EPOCH = 946684800000n; // Date.UTC(2000, 0, 1) == epoch ms, since 1 Jan 2000 00:00\nconst UNSIGNED_23BIT_MAX = 8388607; // (Math.pow(2, 23) - 1) >> 0\n\nconst SIMPLEFLAKE_TIMESTAMP_LENGTH = 41n;\nconst SIMPLEFLAKE_RANDOM_LENGTH = 23n;\n\nconst SIMPLEFLAKE_RANDOM_SHIFT = 0n;\nconst SIMPLEFLAKE_TIMESTAMP_SHIFT = 23n;\n\nconst CACHE_64_BIT_ZEROS =\n \"0000000000000000000000000000000000000000000000000000000000000000\";\n\n/**\n * Generates a simpleflake ID\n * @param ts - Timestamp in milliseconds (defaults to current time)\n * @param randomBits - Random bits for the ID (defaults to a random value)\n * @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)\n * @returns Generated simpleflake as a BigInt\n */\nexport function simpleflake(\n ts: number | bigint = Date.now(),\n randomBits?: number | bigint,\n epoch: number | bigint = SIMPLEFLAKE_EPOCH\n): bigint {\n // Use bitwise OR instead of addition since bit ranges don't overlap\n\n return (\n ((BigInt(ts) - BigInt(epoch)) << SIMPLEFLAKE_TIMESTAMP_SHIFT) |\n BigInt(randomBits ?? Math.round(Math.random() * UNSIGNED_23BIT_MAX))\n );\n}\n\n/**\n * Converts a value to binary representation\n * @param value - The value to convert to binary\n * @param padding - Whether to pad to 64 bits (defaults to true)\n * @returns Binary string representation\n */\nexport function binary(\n value: bigint | number | string,\n padding: boolean = true\n): string {\n const binValue = BigInt(value).toString(2);\n return padding && binValue.length < 64\n ? CACHE_64_BIT_ZEROS.substr(0, 64 - binValue.length) + binValue\n : binValue;\n}\n\n/**\n * Extracts bits from a data value\n * @param data - The data to extract bits from\n * @param shift - Number of bits to shift\n * @param length - Number of bits to extract\n * @returns Extracted bits as a BigInt\n */\nexport function extractBits(\n data: bigint | number | string,\n shift: bigint | number,\n length: bigint | number\n): bigint {\n const shiftN = BigInt(shift);\n const lengthN = BigInt(length);\n // Optimize: shift right first, then mask (avoids creating large bitmask)\n return (BigInt(data) >> shiftN) & ((1n << lengthN) - 1n);\n}\n\n/**\n * Structure representing a parsed simpleflake\n */\nexport class SimpleflakeStruct {\n public readonly timestamp: bigint;\n public readonly randomBits: bigint;\n\n constructor(timestamp: bigint, randomBits: bigint) {\n if (timestamp == null || randomBits == null) {\n throw new Error(\"Missing argument for SimpleflakeStruct.\");\n }\n this.timestamp = timestamp;\n this.randomBits = randomBits;\n }\n}\n\n/**\n * Parses a simpleflake into its components\n * @param flake - The simpleflake to parse\n * @returns SimpleflakeStruct containing timestamp and random bits\n */\nexport function parseSimpleflake(\n flake: bigint | number | string\n): SimpleflakeStruct {\n return new SimpleflakeStruct(\n // timestamp\n extractBits(\n flake,\n SIMPLEFLAKE_TIMESTAMP_SHIFT,\n SIMPLEFLAKE_TIMESTAMP_LENGTH\n ) + SIMPLEFLAKE_EPOCH,\n // random bits\n extractBits(flake, SIMPLEFLAKE_RANDOM_SHIFT, SIMPLEFLAKE_RANDOM_LENGTH)\n );\n}\n\n// Export constants\nexport { SIMPLEFLAKE_EPOCH };\n\n// Default export for CommonJS compatibility\nexport default {\n binary,\n extractBits,\n parseSimpleflake,\n SIMPLEFLAKE_EPOCH,\n simpleflake,\n SimpleflakeStruct,\n};\n"]}
1
+ {"version":3,"sources":["../src/simpleflakes.ts"],"names":["SIMPLEFLAKE_EPOCH","SimpleflakeStruct","binary","extractBits","parseSimpleflake","simpleflake","randomBuffer","Uint32Array","randomBufferIndex","toBigInt","value","BigInt","getRandomSource","globalCrypto","globalThis","crypto","require","webcrypto","Error","refillRandomBuffer","getRandomValues","random23","ts","Date","now","randomBits","epoch","padding","binValue","toString","length","CACHE_64_BIT_ZEROS","substr","data","shift","shiftN","lengthN","timestamp","flake"],"mappings":"uMAsJSA,2BAAAA,uBAlCIC,2BAAAA,uBA/BGC,gBAAAA,YAoEhB,iBAAA,cAnDgBC,qBAAAA,iBAgCAC,0BAAAA,sBApEAC,qBAAAA,eAlEhB,MAAML,kBAAoB,YAAA,AAAa,CAAA,CAmBvC,IAAIM,aAAe,IAAIC,YAjBI,MAkBvBC,kBAlBuB,KAoB3B,SAASC,SAASC,CAA+B,EAC/C,MAAO,AAAiB,UAAjB,OAAOA,EAAqBA,EAAQC,OAAOD,EACpD,CAEA,SAASE,kBACP,IAAMC,EAAe,AAACC,WAEnBC,MAAM,CAET,GAAIF,EAAc,OAAOA,EAEzB,GAAI,CACF,OAAO,AAACG,QACN,eACAC,SAAS,AACb,CAAE,KAAM,CACN,MAAM,AAAIC,MACR,8EAEJ,CACF,CAEA,SAASC,qBACPP,kBAAkBQ,eAAe,CAACd,cAClCE,kBAAoB,CACtB,CAEA,SAASa,WACHb,mBAhDqB,MAiDvBW,qBAEF,IAAMT,EAAQJ,YAAY,CAACE,kBAAkB,CAG7C,OADAA,mBAAqB,EACdG,OAvDkB,AAuDXD,QAAAA,EAChB,CASO,SAASL,YACdiB,EAAsBC,KAAKC,GAAG,EAAE,CAChCC,CAA4B,CAC5BC,EAAyB1B,iBAAiB,EAI1C,OACE,AAAES,SAASa,GAAMb,SAASiB,IAlEM,EAAA,AAAG,CAAA,CAmElCD,CAAAA,AAAc,MAAdA,EAAqBJ,WAAaZ,SAASgB,EAAU,CAE1D,CAQO,SAASvB,OACdQ,CAA+B,CAC/BiB,EAAmB,CAAA,CAAI,EAEvB,IAAMC,EAAWnB,SAASC,GAAOmB,QAAQ,CAAC,GAC1C,OAAOF,GAAWC,EAASE,MAAM,CAAG,GA/EpC,AAgFIC,mEAAmBC,MAAM,CAAC,EAAG,GAAKJ,EAASE,MAAM,EAAIF,EACrDA,CACN,CASO,SAASzB,YACd8B,CAA8B,CAC9BC,CAAsB,CACtBJ,CAAuB,EAEvB,IAAMK,EAAS1B,SAASyB,GAClBE,EAAU3B,SAASqB,GAEzB,OAAO,AAACrB,SAASwB,IAASE,EAAW,AAAC,CAAA,CAAA,AAAE,CAAA,EAAIC,CAAM,EAAK,CAAA,AAAE,CAAA,AAC3D,CAKO,MAAMnC,kBAIX,YAAYoC,CAAiB,CAAEZ,CAAkB,CAAE,CACjD,GAAIY,AAAa,MAAbA,GAAqBZ,AAAc,MAAdA,EACvB,MAAM,AAAIP,MAAM,0CAElB,CAAA,IAAI,CAACmB,SAAS,CAAGA,EACjB,IAAI,CAACZ,UAAU,CAAGA,CACpB,CACF,CAOO,SAASrB,iBACdkC,CAA+B,EAE/B,OAAO,IAAIrC,kBAETE,YACEmC,EApI8B,EAAA,AAAG,CAAA,CAJF,EAAA,AAAG,CAAA,EA2IhCtC,kBAEJG,YAAYmC,EA1IiB,CAAA,AAAE,CAAA,CAFD,EAAA,AAAG,CAAA,EA8IrC,OAMA,SAAe,CACbpC,OACAC,YACAC,iBACAJ,kBACAK,YACAJ,iBACF","file":"simpleflakes.js","sourcesContent":["const SIMPLEFLAKE_EPOCH = 946684800000n; // Date.UTC(2000, 0, 1) == epoch ms, since 1 Jan 2000 00:00\nconst UNSIGNED_23BIT_MAX = 8388607; // (Math.pow(2, 23) - 1) >> 0\nconst RANDOM_BUFFER_SIZE = 1024;\n\nconst SIMPLEFLAKE_TIMESTAMP_LENGTH = 41n;\nconst SIMPLEFLAKE_RANDOM_LENGTH = 23n;\n\nconst SIMPLEFLAKE_RANDOM_SHIFT = 0n;\nconst SIMPLEFLAKE_TIMESTAMP_SHIFT = 23n;\n\nconst CACHE_64_BIT_ZEROS =\n \"0000000000000000000000000000000000000000000000000000000000000000\";\n\ninterface RandomSource {\n getRandomValues<T extends ArrayBufferView>(array: T): T;\n}\n\ndeclare const require: ((moduleName: string) => unknown) | undefined;\n\nlet randomBuffer = new Uint32Array(RANDOM_BUFFER_SIZE);\nlet randomBufferIndex = RANDOM_BUFFER_SIZE;\n\nfunction toBigInt(value: bigint | number | string): bigint {\n return typeof value === \"bigint\" ? value : BigInt(value);\n}\n\nfunction getRandomSource(): RandomSource {\n const globalCrypto = (globalThis as typeof globalThis & {\n crypto?: RandomSource;\n }).crypto;\n\n if (globalCrypto) return globalCrypto;\n\n try {\n return (require as (moduleName: string) => { webcrypto: RandomSource })(\n [\"node\", \"crypto\"].join(\":\")\n ).webcrypto;\n } catch {\n throw new Error(\n \"Cryptographically secure random values are unavailable in this environment.\"\n );\n }\n}\n\nfunction refillRandomBuffer(): void {\n getRandomSource().getRandomValues(randomBuffer);\n randomBufferIndex = 0;\n}\n\nfunction random23(): bigint {\n if (randomBufferIndex >= RANDOM_BUFFER_SIZE) {\n refillRandomBuffer();\n }\n const value = randomBuffer[randomBufferIndex]!;\n\n randomBufferIndex += 1;\n return BigInt(value & UNSIGNED_23BIT_MAX);\n}\n\n/**\n * Generates a simpleflake ID\n * @param ts - Timestamp in milliseconds (defaults to current time)\n * @param randomBits - Random bits for the ID (defaults to a cryptographically secure random value)\n * @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)\n * @returns Generated simpleflake as a BigInt\n */\nexport function simpleflake(\n ts: number | bigint = Date.now(),\n randomBits?: number | bigint,\n epoch: number | bigint = SIMPLEFLAKE_EPOCH\n): bigint {\n // Use bitwise OR instead of addition since bit ranges don't overlap\n\n return (\n ((toBigInt(ts) - toBigInt(epoch)) << SIMPLEFLAKE_TIMESTAMP_SHIFT) |\n (randomBits == null ? random23() : toBigInt(randomBits))\n );\n}\n\n/**\n * Converts a value to binary representation\n * @param value - The value to convert to binary\n * @param padding - Whether to pad to 64 bits (defaults to true)\n * @returns Binary string representation\n */\nexport function binary(\n value: bigint | number | string,\n padding: boolean = true\n): string {\n const binValue = toBigInt(value).toString(2);\n return padding && binValue.length < 64\n ? CACHE_64_BIT_ZEROS.substr(0, 64 - binValue.length) + binValue\n : binValue;\n}\n\n/**\n * Extracts bits from a data value\n * @param data - The data to extract bits from\n * @param shift - Number of bits to shift\n * @param length - Number of bits to extract\n * @returns Extracted bits as a BigInt\n */\nexport function extractBits(\n data: bigint | number | string,\n shift: bigint | number,\n length: bigint | number\n): bigint {\n const shiftN = toBigInt(shift);\n const lengthN = toBigInt(length);\n // Optimize: shift right first, then mask (avoids creating large bitmask)\n return (toBigInt(data) >> shiftN) & ((1n << lengthN) - 1n);\n}\n\n/**\n * Structure representing a parsed simpleflake\n */\nexport class SimpleflakeStruct {\n public declare readonly timestamp: bigint;\n public declare readonly randomBits: bigint;\n\n constructor(timestamp: bigint, randomBits: bigint) {\n if (timestamp == null || randomBits == null) {\n throw new Error(\"Missing argument for SimpleflakeStruct.\");\n }\n this.timestamp = timestamp;\n this.randomBits = randomBits;\n }\n}\n\n/**\n * Parses a simpleflake into its components\n * @param flake - The simpleflake to parse\n * @returns SimpleflakeStruct containing timestamp and random bits\n */\nexport function parseSimpleflake(\n flake: bigint | number | string\n): SimpleflakeStruct {\n return new SimpleflakeStruct(\n // timestamp\n extractBits(\n flake,\n SIMPLEFLAKE_TIMESTAMP_SHIFT,\n SIMPLEFLAKE_TIMESTAMP_LENGTH\n ) + SIMPLEFLAKE_EPOCH,\n // random bits\n extractBits(flake, SIMPLEFLAKE_RANDOM_SHIFT, SIMPLEFLAKE_RANDOM_LENGTH)\n );\n}\n\n// Export constants\nexport { SIMPLEFLAKE_EPOCH };\n\n// Default export for CommonJS compatibility\nexport default {\n binary,\n extractBits,\n parseSimpleflake,\n SIMPLEFLAKE_EPOCH,\n simpleflake,\n SimpleflakeStruct,\n};\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "simpleflakes",
3
- "version": "4.0.0",
4
- "description": "Fast, lightweight, and reliable distributed 64-bit ID generation with zero dependencies for Node.js.",
3
+ "version": "4.1.1",
4
+ "description": "Fast, lightweight, and reliable distributed 64-bit ID generation with zero dependencies for Node.js and the web.",
5
5
  "main": "dist/simpleflakes.js",
6
6
  "types": "dist/simpleflakes.d.ts",
7
7
  "files": [
@@ -33,19 +33,24 @@
33
33
  "keywords": [
34
34
  "simpleflake",
35
35
  "snowflake",
36
- "flake",
37
- "id",
36
+ "snowflake-id",
37
+ "id-generator",
38
+ "unique-id",
39
+ "sortable-id",
40
+ "time-ordered",
41
+ "64-bit",
42
+ "bigint",
43
+ "distributed-id",
44
+ "database-id",
38
45
  "uuid",
39
- "sequential",
40
- "monotonic",
41
- "ksuid",
42
- "nanoid",
43
46
  "uuidv7",
44
- "database",
45
- "distributed",
46
- "bigint",
47
- "time-ordered",
48
- "typescript"
47
+ "nanoid",
48
+ "ksuid",
49
+ "webcrypto",
50
+ "zero-dependency",
51
+ "typescript",
52
+ "nodejs",
53
+ "browser"
49
54
  ],
50
55
  "author": {
51
56
  "name": "Leonardo Dutra",