simpleflakes 2.2.2 → 3.0.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 +340 -68
- package/dist/simpleflakes.d.ts +51 -0
- package/dist/simpleflakes.d.ts.map +1 -0
- package/dist/simpleflakes.js +91 -0
- package/dist/simpleflakes.js.map +1 -0
- package/lib/simpleflakes.js +1 -1
- package/package.json +38 -11
- package/.eslintrc.js +0 -20
- package/.travis.yml +0 -24
- package/benchmark/run.js +0 -59
- package/index.js +0 -3
- package/lib/simpleflakes-legacy.js +0 -70
- package/tests/simpleflakes-legacy.tests..js +0 -76
- package/tests/simpleflakes.tests.js +0 -65
package/README.md
CHANGED
|
@@ -1,105 +1,377 @@
|
|
|
1
1
|
# simpleflakes
|
|
2
2
|
|
|
3
|
-
[](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml)
|
|
4
4
|
[![npm][npm-badge]][npm-link]
|
|
5
|
-
|
|
6
|
-
[](https://www.npmjs.com/package/simpleflakes)
|
|
6
|
+
[](https://bundlephobia.com/package/simpleflakes)
|
|
7
|
+
[](https://github.com/leodutra/simpleflakes/actions/workflows/ci.yml)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
[](https://www.npmjs.com/package/simpleflakes)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](https://github.com/leodutra/simpleflakes)
|
|
7
12
|
[![coveralls status][coveralls-badge]][coveralls-link] [](https://app.fossa.io/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes?ref=badge_shield)
|
|
8
|
-
|
|
9
|
-
[![tonicdev demo][demo-tonicdev-badge]][demo-tonicdev-link]
|
|
10
|
-
[![david dep status][dependencies-badge]][dependencies-url]
|
|
11
|
-
[![david dev dep status][dependencies-dev-badge]][dependencies-dev-url]
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
> **Fast, reliable, distributed 64-bit ID generation for Node.js** ⚡
|
|
15
|
+
> Zero dependencies • TypeScript-ready • 8.8M+ ops/sec performance
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
This port is test-driven and no release goes out without tests.
|
|
17
|
-
**Also, this library does not rely on low-level bindings, with OpenSSL, libgmp or anything beyond pure JavaScript.**
|
|
17
|
+
## ✨ Features
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- 🚀 **Ultra-fast**: 8.8M+ operations per second
|
|
20
|
+
- 🔢 **64-bit time-ordered IDs**: Globally unique, sortable by creation time
|
|
21
|
+
- 📦 **Zero dependencies**: Pure JavaScript implementation
|
|
22
|
+
- 🏷️ **TypeScript-first**: Full type safety and IntelliSense support
|
|
23
|
+
- 🌐 **Universal**: Works with CommonJS, ES Modules, and TypeScript
|
|
24
|
+
- ⚖️ **Lightweight**: Tiny bundle size, tree-shakable
|
|
25
|
+
- 🧪 **Battle-tested**: 100% test coverage, production-ready
|
|
26
|
+
- 🔄 **Snowflake compatible**: Drop-in replacement for Twitter Snowflake
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
## 🏗️ What is Simpleflake?
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
Simpleflake generates **unique 64-bit integers** that are:
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
1. **Time-ordered** - IDs generated later are numerically larger
|
|
33
|
+
2. **Distributed-safe** - No coordination needed between multiple generators
|
|
34
|
+
3. **Compact** - Fits in a 64-bit integer (vs UUID's 128 bits)
|
|
35
|
+
4. **URL-friendly** - Can be represented as short strings
|
|
36
|
+
|
|
37
|
+
Perfect for database primary keys, distributed system IDs, and anywhere you need fast, unique identifiers.
|
|
38
|
+
|
|
39
|
+
[See the original presentation!](http://akmanalp.com/simpleflake_presentation/)
|
|
40
|
+
|
|
41
|
+
## 📦 Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install simpleflakes
|
|
27
45
|
```
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
## 🚀 Quick Start
|
|
48
|
+
|
|
49
|
+
### JavaScript (CommonJS)
|
|
50
|
+
```javascript
|
|
31
51
|
const { simpleflake } = require('simpleflakes');
|
|
32
52
|
|
|
33
|
-
|
|
53
|
+
// Generate a unique ID
|
|
54
|
+
const id = simpleflake();
|
|
55
|
+
console.log(id); // 4234673179811182512n (BigInt)
|
|
56
|
+
|
|
57
|
+
// Convert to different formats
|
|
58
|
+
console.log(id.toString()); // "4234673179811182512"
|
|
59
|
+
console.log(id.toString(16)); // "3ac494d21e84f7b0" (hex)
|
|
60
|
+
console.log(id.toString(36)); // "20rfh5bt4k0g" (base36 - shortest)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### TypeScript / ES Modules
|
|
64
|
+
```typescript
|
|
65
|
+
import { simpleflake, parseSimpleflake, type SimpleFlakeStruct } from 'simpleflakes';
|
|
66
|
+
|
|
67
|
+
// Generate with full type safety
|
|
68
|
+
const id: bigint = simpleflake();
|
|
69
|
+
|
|
70
|
+
// Parse the ID to extract timestamp and random bits
|
|
71
|
+
const parsed: SimpleFlakeStruct = parseSimpleflake(id);
|
|
72
|
+
console.log(parsed.timestamp); // "1693244847123" (Unix timestamp as string)
|
|
73
|
+
console.log(parsed.randomBits); // "4567234" (Random component as string)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 🎯 Advanced Usage
|
|
77
|
+
|
|
78
|
+
### Custom Parameters
|
|
79
|
+
```javascript
|
|
80
|
+
// Generate with custom timestamp and random bits
|
|
81
|
+
const customId = simpleflake(
|
|
82
|
+
Date.now(), // timestamp (default: Date.now())
|
|
83
|
+
12345, // random bits (default: 23-bit random)
|
|
84
|
+
Date.UTC(2000, 0, 1) // epoch (default: Year 2000)
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Working with Binary Data
|
|
89
|
+
```javascript
|
|
90
|
+
import { binary, extractBits } from 'simpleflakes';
|
|
91
|
+
|
|
92
|
+
const id = simpleflake();
|
|
93
|
+
|
|
94
|
+
// View binary representation
|
|
95
|
+
console.log(binary(id));
|
|
96
|
+
// Output: "0011101011000100100100110100001000011110100001001111011110110000"
|
|
97
|
+
|
|
98
|
+
// Extract specific bit ranges
|
|
99
|
+
const timestampBits = extractBits(id, 23n, 41n); // Extract 41 bits starting at position 23
|
|
100
|
+
const randomBits = extractBits(id, 0n, 23n); // Extract first 23 bits
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Batch Generation
|
|
104
|
+
```javascript
|
|
105
|
+
// Generate multiple IDs efficiently
|
|
106
|
+
function generateBatch(count) {
|
|
107
|
+
const ids = [];
|
|
108
|
+
for (let i = 0; i < count; i++) {
|
|
109
|
+
ids.push(simpleflake());
|
|
110
|
+
}
|
|
111
|
+
return ids;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const batch = generateBatch(1000);
|
|
115
|
+
console.log(`Generated ${batch.length} unique IDs`);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 🔬 ID Structure
|
|
119
|
+
|
|
120
|
+
Each 64-bit simpleflake ID contains:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
|-- 41 bits ---|-- 23 bits --|
|
|
124
|
+
| Timestamp | Random |
|
|
125
|
+
| (milliseconds)| (0-8388607) |
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- **41 bits timestamp**: Milliseconds since epoch (Year 2000)
|
|
129
|
+
- **23 bits random**: Random number for uniqueness within the same millisecond
|
|
130
|
+
- **Total**: 64 bits = fits in a signed 64-bit integer
|
|
131
|
+
|
|
132
|
+
This gives you:
|
|
133
|
+
- **69+ years** of timestamp range (until year 2069)
|
|
134
|
+
- **8.3 million** unique IDs per millisecond
|
|
135
|
+
- **Sortable by creation time** when converted to integers
|
|
136
|
+
|
|
137
|
+
## ⚡ Performance
|
|
138
|
+
|
|
139
|
+
Simpleflakes is optimized for speed:
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
// Benchmark results (operations per second)
|
|
143
|
+
simpleflake() // ~8.8M ops/sec
|
|
144
|
+
parseSimpleflake() // ~3.9M ops/sec
|
|
145
|
+
binary() // ~26M ops/sec
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Perfect for high-throughput applications requiring millions of IDs per second.
|
|
149
|
+
|
|
150
|
+
## 🏛️ Architecture
|
|
151
|
+
|
|
152
|
+
### Why 64-bit IDs?
|
|
153
|
+
|
|
154
|
+
- **Database-friendly**: Most databases optimize for 64-bit integers
|
|
155
|
+
- **Memory efficient**: Half the size of UUIDs (128-bit)
|
|
156
|
+
- **Performance**: Integer operations are faster than string operations
|
|
157
|
+
- **Sortable**: Natural ordering by creation time
|
|
158
|
+
- **Compact URLs**: Shorter than UUIDs when base36-encoded
|
|
159
|
+
|
|
160
|
+
### Distributed Generation
|
|
161
|
+
|
|
162
|
+
No coordination required between multiple ID generators:
|
|
163
|
+
- **Clock skew tolerant**: Small time differences between servers are fine
|
|
164
|
+
- **Random collision protection**: 23 random bits provide 8.3M combinations per millisecond
|
|
165
|
+
- **High availability**: Each service can generate IDs independently
|
|
166
|
+
|
|
167
|
+
## 🧪 API Reference
|
|
168
|
+
|
|
169
|
+
### Core Functions
|
|
170
|
+
|
|
171
|
+
#### `simpleflake(timestamp?, randomBits?, epoch?): bigint`
|
|
172
|
+
Generates a unique 64-bit ID.
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
- `timestamp` (number, optional): Unix timestamp in milliseconds. Default: `Date.now()`
|
|
176
|
+
- `randomBits` (number, optional): Random bits (0-8388607). Default: random 23-bit number
|
|
177
|
+
- `epoch` (number, optional): Epoch start time. Default: `Date.UTC(2000, 0, 1)`
|
|
178
|
+
|
|
179
|
+
**Returns:** BigInt - The generated ID
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
const id = simpleflake();
|
|
183
|
+
const customId = simpleflake(Date.now(), 12345, Date.UTC(2000, 0, 1));
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### `parseSimpleflake(flake): SimpleFlakeStruct`
|
|
187
|
+
Parses a simpleflake ID into its components.
|
|
188
|
+
|
|
189
|
+
**Parameters:**
|
|
190
|
+
- `flake` (bigint | string | number): The ID to parse
|
|
34
191
|
|
|
35
|
-
|
|
36
|
-
// timestamp = Date.now(),
|
|
37
|
-
// random_bits = 23-bit random,
|
|
38
|
-
// epoch = Date.UTC(2000, 0, 1)
|
|
39
|
-
// )
|
|
40
|
-
// returns BigInt on newer Node.js or bn.js BigNum on older engines.
|
|
192
|
+
**Returns:** Object with `timestamp` and `randomBits` properties (both strings)
|
|
41
193
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
194
|
+
```javascript
|
|
195
|
+
const parsed = parseSimpleflake(4234673179811182512n);
|
|
196
|
+
console.log(parsed.timestamp); // "1693244847123"
|
|
197
|
+
console.log(parsed.randomBits); // "4567234"
|
|
46
198
|
```
|
|
47
|
-
You can check the [original Python API 0.1.5](https://simpleflake.readthedocs.org/en/latest/) documentation for more info.
|
|
48
199
|
|
|
200
|
+
#### `binary(value, padding?): string`
|
|
201
|
+
Converts a number to binary string representation.
|
|
49
202
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
simpleflake(
|
|
54
|
-
timestamp = Date.now(),
|
|
55
|
-
random_bits = 23-bit random,
|
|
56
|
-
epoch = Date.UTC(2000, 0, 1)
|
|
57
|
-
)
|
|
203
|
+
**Parameters:**
|
|
204
|
+
- `value` (bigint | string | number): Value to convert
|
|
205
|
+
- `padding` (boolean, optional): Whether to pad to 64 bits. Default: `true`
|
|
58
206
|
|
|
59
|
-
|
|
60
|
-
simpleflake.SIMPLEFLAKE_EPOCH // const = 946702800
|
|
207
|
+
**Returns:** String - Binary representation
|
|
61
208
|
|
|
62
|
-
|
|
63
|
-
|
|
209
|
+
```javascript
|
|
210
|
+
console.log(binary(42n)); // "0000000000000000000000000000000000000000000000000000000000101010"
|
|
211
|
+
console.log(binary(42n, false)); // "101010"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### `extractBits(data, shift, length): bigint`
|
|
215
|
+
Extracts a portion of bits from a number.
|
|
216
|
+
|
|
217
|
+
**Parameters:**
|
|
218
|
+
- `data` (bigint | string | number): Source data
|
|
219
|
+
- `shift` (bigint): Starting bit position (0-based from right)
|
|
220
|
+
- `length` (bigint): Number of bits to extract
|
|
221
|
+
|
|
222
|
+
**Returns:** BigInt - Extracted bits as number
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
const bits = extractBits(0b11110000n, 4n, 4n); // Extract 4 bits starting at position 4
|
|
226
|
+
console.log(bits); // 15n (0b1111)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Constants
|
|
230
|
+
|
|
231
|
+
#### `SIMPLEFLAKE_EPOCH: number`
|
|
232
|
+
The epoch start time (January 1, 2000 UTC) as Unix timestamp.
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
import { SIMPLEFLAKE_EPOCH } from 'simpleflakes';
|
|
236
|
+
console.log(SIMPLEFLAKE_EPOCH); // 946684800000
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### TypeScript Types
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
interface SimpleFlakeStruct {
|
|
243
|
+
timestamp: string; // Unix timestamp as string
|
|
244
|
+
randomBits: string; // Random component as string
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## 🔄 Migration Guide
|
|
249
|
+
|
|
250
|
+
### From UUID
|
|
251
|
+
```javascript
|
|
252
|
+
// Before (UUID v4)
|
|
253
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
254
|
+
const id = uuidv4(); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
255
|
+
|
|
256
|
+
// After (Simpleflake)
|
|
257
|
+
import { simpleflake } from 'simpleflakes';
|
|
258
|
+
const id = simpleflake().toString(36); // "20rfh5bt4k0g" (shorter!)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### From Twitter Snowflake
|
|
262
|
+
```javascript
|
|
263
|
+
// Simpleflake is backwards compatible with Snowflake structure
|
|
264
|
+
// Just different bit allocation:
|
|
265
|
+
// - Snowflake: 41 bits timestamp + 10 bits machine + 12 bits sequence
|
|
266
|
+
// - Simpleflake: 41 bits timestamp + 23 bits random
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 📖 Use Cases
|
|
270
|
+
|
|
271
|
+
### Database Primary Keys
|
|
272
|
+
```javascript
|
|
273
|
+
// Perfect for database IDs - time-ordered and unique
|
|
274
|
+
const userId = simpleflake();
|
|
275
|
+
await db.users.create({ id: userId.toString(), name: "John" });
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Distributed System IDs
|
|
279
|
+
```javascript
|
|
280
|
+
// Each service can generate IDs independently
|
|
281
|
+
const serviceAId = simpleflake(); // Service A
|
|
282
|
+
const serviceBId = simpleflake(); // Service B
|
|
283
|
+
// No coordination needed, guaranteed unique across services
|
|
284
|
+
```
|
|
64
285
|
|
|
65
|
-
|
|
66
|
-
|
|
286
|
+
### Short URLs
|
|
287
|
+
```javascript
|
|
288
|
+
// Generate compact URL identifiers
|
|
289
|
+
const shortId = simpleflake().toString(36); // "20rfh5bt4k0g"
|
|
290
|
+
const url = `https://short.ly/${shortId}`;
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Event Tracking
|
|
294
|
+
```javascript
|
|
295
|
+
// Time-ordered event IDs for chronological processing
|
|
296
|
+
const eventId = simpleflake();
|
|
297
|
+
await analytics.track({ eventId, userId, action: "click" });
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## 🔧 Development
|
|
301
|
+
|
|
302
|
+
This project is written in TypeScript and includes comprehensive test coverage.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# Install dependencies
|
|
306
|
+
npm install
|
|
67
307
|
|
|
68
|
-
|
|
69
|
-
|
|
308
|
+
# Build TypeScript to JavaScript
|
|
309
|
+
npm run build
|
|
70
310
|
|
|
71
|
-
|
|
72
|
-
|
|
311
|
+
# Run tests (automatically builds first)
|
|
312
|
+
npm test
|
|
73
313
|
|
|
74
|
-
|
|
75
|
-
|
|
314
|
+
# Run with coverage
|
|
315
|
+
npm run test:coverage
|
|
316
|
+
|
|
317
|
+
# Test module compatibility (CommonJS, ES Modules, TypeScript)
|
|
318
|
+
npm run test:compatibility
|
|
319
|
+
|
|
320
|
+
# Run all CI tests (coverage + compatibility)
|
|
321
|
+
npm run test:ci
|
|
322
|
+
|
|
323
|
+
# Type checking
|
|
324
|
+
npm run type-check
|
|
325
|
+
|
|
326
|
+
# Run benchmarks
|
|
327
|
+
npm run benchmark
|
|
328
|
+
|
|
329
|
+
# Clean build artifacts
|
|
330
|
+
npm run clean
|
|
76
331
|
```
|
|
77
332
|
|
|
333
|
+
## 📚 References
|
|
334
|
+
|
|
335
|
+
- **[Original Presentation](http://akmanalp.com/simpleflake_presentation/)** - Introduction to the concept
|
|
336
|
+
- **[Python Implementation](https://simpleflake.readthedocs.org/en/latest/)** - Original reference implementation
|
|
337
|
+
- **[Twitter Snowflake](https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake.html)** - Similar distributed ID system
|
|
338
|
+
|
|
339
|
+
## 🆚 Comparison
|
|
340
|
+
|
|
341
|
+
| Feature | Simpleflakes | UUID v4 | Twitter Snowflake |
|
|
342
|
+
|---------|-------------|---------|------------------|
|
|
343
|
+
| **Size** | 64-bit | 128-bit | 64-bit |
|
|
344
|
+
| **Time-ordered** | ✅ Yes | ❌ No | ✅ Yes |
|
|
345
|
+
| **Distributed** | ✅ Yes | ✅ Yes | ⚠️ Needs config |
|
|
346
|
+
| **Dependencies** | ✅ Zero | ❌ crypto | ❌ System clock |
|
|
347
|
+
| **Performance** | 🚀 8.8M/sec | 🐌 ~2M/sec | 🚀 ~10M/sec |
|
|
348
|
+
| **URL-friendly** | ✅ Base36 | ❌ Long hex | ✅ Base36 |
|
|
349
|
+
| **Database-friendly** | ✅ Integer | ❌ String | ✅ Integer |
|
|
350
|
+
|
|
351
|
+
## 🤝 Contributing
|
|
352
|
+
|
|
353
|
+
1. Fork the repository
|
|
354
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
355
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
356
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
357
|
+
5. Open a Pull Request
|
|
358
|
+
|
|
359
|
+
## 📄 License
|
|
78
360
|
|
|
79
|
-
### License:
|
|
80
361
|
[MIT](https://raw.githubusercontent.com/leodutra/simpleflakes/master/LICENSE)
|
|
81
362
|
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## 🏷️ Credits
|
|
366
|
+
|
|
367
|
+
- Original concept by [Mali Akmanalp](http://akmanalp.com/)
|
|
368
|
+
- TypeScript port and optimizations by [Leo Dutra](https://github.com/leodutra)
|
|
369
|
+
- Inspired by [Twitter Snowflake](https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake.html)
|
|
370
|
+
|
|
82
371
|
[npm-badge]: https://img.shields.io/npm/v/simpleflakes.svg?style=flat
|
|
83
|
-
[travis-badge]: http://img.shields.io/travis/leodutra/simpleflakes.svg?style=flat
|
|
84
|
-
[codacy-coverage-badge]: https://api.codacy.com/project/badge/Coverage/f71ef817e5f14a9ab3b8b2cb6fabf51a
|
|
85
|
-
[codacy-quality-badge]: https://api.codacy.com/project/badge/Grade/f71ef817e5f14a9ab3b8b2cb6fabf51a
|
|
86
372
|
[coveralls-badge]: https://img.shields.io/coveralls/leodutra/simpleflakes.svg?style=flat
|
|
87
373
|
|
|
88
374
|
[npm-link]: https://www.npmjs.com/package/simpleflakes
|
|
89
|
-
[travis-link]: https://travis-ci.org/leodutra/simpleflakes
|
|
90
|
-
[codacy-quality-link]: https://www.codacy.com/app/leodutra/simpleflakes
|
|
91
|
-
|
|
92
|
-
[codacy-coverage-link]: https://www.codacy.com/app/leodutra/simpleflakes?utm_source=github.com&utm_medium=referral&utm_content=leodutra/simpleflakes&utm_campaign=Badge_Coverage
|
|
93
|
-
[codacy-quality-link]: https://www.codacy.com/app/leodutra/simpleflakes?utm_source=github.com&utm_medium=referral&utm_content=leodutra/simpleflakes&utm_campaign=Badge_Grade
|
|
94
375
|
[coveralls-link]: https://coveralls.io/github/leodutra/simpleflakes
|
|
95
|
-
[demo-tonicdev-link]: https://tonicdev.com/leodutra/simpleflakes-demo/1.0.13
|
|
96
|
-
|
|
97
|
-
[dependencies-url]: https://david-dm.org/leodutra/simpleflakes
|
|
98
|
-
[dependencies-badge]: https://img.shields.io/david/leodutra/simpleflakes.svg?style=flat
|
|
99
|
-
[dependencies-dev-url]: https://david-dm.org/leodutra/simpleflakes#info=devDependencies&view=table
|
|
100
|
-
[dependencies-dev-badge]: https://img.shields.io/david/dev/leodutra/simpleflakes.svg?style=flat
|
|
101
|
-
[demo-tonicdev-badge]: https://img.shields.io/badge/demo-%40tonicdev-008bb8.svg?style=flat
|
|
102
|
-
|
|
103
|
-
|
|
104
376
|
|
|
105
377
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fleodutra%2Fsimpleflakes?ref=badge_large)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare const SIMPLEFLAKE_EPOCH = 946684800000;
|
|
2
|
+
/**
|
|
3
|
+
* Generates a simpleflake ID
|
|
4
|
+
* @param ts - Timestamp in milliseconds (defaults to current time)
|
|
5
|
+
* @param randomBits - Random bits for the ID (defaults to a random value)
|
|
6
|
+
* @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)
|
|
7
|
+
* @returns Generated simpleflake as a BigInt
|
|
8
|
+
*/
|
|
9
|
+
export declare function simpleflake(ts?: number, randomBits?: number, epoch?: number): bigint;
|
|
10
|
+
/**
|
|
11
|
+
* Converts a value to binary representation
|
|
12
|
+
* @param value - The value to convert to binary
|
|
13
|
+
* @param padding - Whether to pad to 64 bits (defaults to true)
|
|
14
|
+
* @returns Binary string representation
|
|
15
|
+
*/
|
|
16
|
+
export declare function binary(value: bigint | number | string, padding?: boolean): string;
|
|
17
|
+
/**
|
|
18
|
+
* Extracts bits from a data value
|
|
19
|
+
* @param data - The data to extract bits from
|
|
20
|
+
* @param shift - Number of bits to shift
|
|
21
|
+
* @param length - Number of bits to extract
|
|
22
|
+
* @returns Extracted bits as a BigInt
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractBits(data: bigint | number | string, shift: bigint | number, length: bigint | number): bigint;
|
|
25
|
+
/**
|
|
26
|
+
* Structure representing a parsed simpleflake
|
|
27
|
+
*/
|
|
28
|
+
export declare class SimpleFlakeStruct {
|
|
29
|
+
readonly timestamp: string;
|
|
30
|
+
readonly randomBits: string;
|
|
31
|
+
constructor(timestamp: string, randomBits: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parses a simpleflake into its components
|
|
35
|
+
* @param flake - The simpleflake to parse
|
|
36
|
+
* @returns SimpleFlakeStruct containing timestamp and random bits
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseSimpleflake(flake: bigint | number | string): SimpleFlakeStruct;
|
|
39
|
+
export declare const simpleflakeStruct: typeof SimpleFlakeStruct;
|
|
40
|
+
export { SIMPLEFLAKE_EPOCH };
|
|
41
|
+
declare const _default: {
|
|
42
|
+
SimpleFlakeStruct: typeof SimpleFlakeStruct;
|
|
43
|
+
simpleflakeStruct: typeof SimpleFlakeStruct;
|
|
44
|
+
extractBits: typeof extractBits;
|
|
45
|
+
parseSimpleflake: typeof parseSimpleflake;
|
|
46
|
+
binary: typeof binary;
|
|
47
|
+
SIMPLEFLAKE_EPOCH: number;
|
|
48
|
+
simpleflake: typeof simpleflake;
|
|
49
|
+
};
|
|
50
|
+
export default _default;
|
|
51
|
+
//# sourceMappingURL=simpleflakes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simpleflakes.d.ts","sourceRoot":"","sources":["../src/simpleflakes.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,iBAAiB,eAAe,CAAC;AAWvC;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,GAAE,MAAmB,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAA0B,GAAG,MAAM,CAGnH;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,OAAc,GAAG,MAAM,CAKvF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAInH;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,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,iBAAiB,CAQnF;AAGD,eAAO,MAAM,iBAAiB,0BAAoB,CAAC;AAGnD,OAAO,EAAE,iBAAiB,EAAE,CAAC;;;;;;;;;;AAG7B,wBAWE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SIMPLEFLAKE_EPOCH = exports.simpleflakeStruct = exports.SimpleFlakeStruct = void 0;
|
|
4
|
+
exports.simpleflake = simpleflake;
|
|
5
|
+
exports.binary = binary;
|
|
6
|
+
exports.extractBits = extractBits;
|
|
7
|
+
exports.parseSimpleflake = parseSimpleflake;
|
|
8
|
+
const SIMPLEFLAKE_EPOCH = 946684800000; // Date.UTC(2000, 0, 1) == epoch ms, since 1 Jan 2000 00:00
|
|
9
|
+
exports.SIMPLEFLAKE_EPOCH = SIMPLEFLAKE_EPOCH;
|
|
10
|
+
const UNSIGNED_23BIT_MAX = 8388607; // (Math.pow(2, 23) - 1) >> 0
|
|
11
|
+
const SIMPLEFLAKE_TIMESTAMP_LENGTH = 41n;
|
|
12
|
+
const SIMPLEFLAKE_RANDOM_LENGTH = 23n;
|
|
13
|
+
const SIMPLEFLAKE_RANDOM_SHIFT = 0n;
|
|
14
|
+
const SIMPLEFLAKE_TIMESTAMP_SHIFT = 23n;
|
|
15
|
+
const CACHE_64_BIT_ZEROS = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
16
|
+
/**
|
|
17
|
+
* Generates a simpleflake ID
|
|
18
|
+
* @param ts - Timestamp in milliseconds (defaults to current time)
|
|
19
|
+
* @param randomBits - Random bits for the ID (defaults to a random value)
|
|
20
|
+
* @param epoch - Epoch timestamp in milliseconds (defaults to SIMPLEFLAKE_EPOCH)
|
|
21
|
+
* @returns Generated simpleflake as a BigInt
|
|
22
|
+
*/
|
|
23
|
+
function simpleflake(ts = Date.now(), randomBits, epoch = SIMPLEFLAKE_EPOCH) {
|
|
24
|
+
return ((BigInt(ts) - BigInt(epoch)) << SIMPLEFLAKE_TIMESTAMP_SHIFT) +
|
|
25
|
+
BigInt(randomBits ?? Math.round(Math.random() * UNSIGNED_23BIT_MAX));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Converts a value to binary representation
|
|
29
|
+
* @param value - The value to convert to binary
|
|
30
|
+
* @param padding - Whether to pad to 64 bits (defaults to true)
|
|
31
|
+
* @returns Binary string representation
|
|
32
|
+
*/
|
|
33
|
+
function binary(value, padding = true) {
|
|
34
|
+
const binValue = BigInt(value).toString(2);
|
|
35
|
+
return padding && binValue.length < 64
|
|
36
|
+
? CACHE_64_BIT_ZEROS.substr(0, 64 - binValue.length) + binValue
|
|
37
|
+
: binValue;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Extracts bits from a data value
|
|
41
|
+
* @param data - The data to extract bits from
|
|
42
|
+
* @param shift - Number of bits to shift
|
|
43
|
+
* @param length - Number of bits to extract
|
|
44
|
+
* @returns Extracted bits as a BigInt
|
|
45
|
+
*/
|
|
46
|
+
function extractBits(data, shift, length) {
|
|
47
|
+
const shiftN = BigInt(shift);
|
|
48
|
+
const bitmask = ((1n << BigInt(length)) - 1n) << shiftN;
|
|
49
|
+
return (BigInt(data) & bitmask) >> shiftN;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Structure representing a parsed simpleflake
|
|
53
|
+
*/
|
|
54
|
+
class SimpleFlakeStruct {
|
|
55
|
+
constructor(timestamp, randomBits) {
|
|
56
|
+
if (timestamp == null || randomBits == null) {
|
|
57
|
+
throw new Error('Missing argument for SimpleFlakeStruct.');
|
|
58
|
+
}
|
|
59
|
+
this.timestamp = timestamp;
|
|
60
|
+
this.randomBits = randomBits;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.SimpleFlakeStruct = SimpleFlakeStruct;
|
|
64
|
+
/**
|
|
65
|
+
* Parses a simpleflake into its components
|
|
66
|
+
* @param flake - The simpleflake to parse
|
|
67
|
+
* @returns SimpleFlakeStruct containing timestamp and random bits
|
|
68
|
+
*/
|
|
69
|
+
function parseSimpleflake(flake) {
|
|
70
|
+
return new SimpleFlakeStruct(
|
|
71
|
+
// timestamp
|
|
72
|
+
(extractBits(flake, SIMPLEFLAKE_TIMESTAMP_SHIFT, SIMPLEFLAKE_TIMESTAMP_LENGTH)
|
|
73
|
+
+ BigInt(SIMPLEFLAKE_EPOCH)).toString(10),
|
|
74
|
+
// random bits
|
|
75
|
+
extractBits(flake, SIMPLEFLAKE_RANDOM_SHIFT, SIMPLEFLAKE_RANDOM_LENGTH).toString(10));
|
|
76
|
+
}
|
|
77
|
+
// Legacy function alias for backwards compatibility
|
|
78
|
+
exports.simpleflakeStruct = SimpleFlakeStruct;
|
|
79
|
+
// Default export for CommonJS compatibility
|
|
80
|
+
exports.default = {
|
|
81
|
+
// Enhancements
|
|
82
|
+
SimpleFlakeStruct: SimpleFlakeStruct,
|
|
83
|
+
// original API
|
|
84
|
+
simpleflakeStruct: SimpleFlakeStruct,
|
|
85
|
+
extractBits: extractBits,
|
|
86
|
+
parseSimpleflake: parseSimpleflake,
|
|
87
|
+
binary: binary,
|
|
88
|
+
SIMPLEFLAKE_EPOCH: SIMPLEFLAKE_EPOCH,
|
|
89
|
+
simpleflake: simpleflake
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=simpleflakes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simpleflakes.js","sourceRoot":"","sources":["../src/simpleflakes.ts"],"names":[],"mappings":"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"}
|
package/lib/simpleflakes.js
CHANGED
|
@@ -11,7 +11,7 @@ const CACHE_64_BIT_ZEROS = '0000000000000000000000000000000000000000000000000000
|
|
|
11
11
|
|
|
12
12
|
function simpleflake(ts = Date.now(), randomBits, epoch = SIMPLEFLAKE_EPOCH) {
|
|
13
13
|
return ((BigInt(ts) - BigInt(epoch)) << SIMPLEFLAKE_TIMESTAMP_SHIFT) +
|
|
14
|
-
BigInt(randomBits
|
|
14
|
+
BigInt(randomBits ?? Math.round(Math.random() * UNSIGNED_23BIT_MAX));
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function binary(value, padding = true) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simpleflakes",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Fast, and reliable, distributed 64-bit ID generation, in pure JavaScript, for Node.js.",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "dist/simpleflakes.js",
|
|
6
|
+
"types": "dist/simpleflakes.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/",
|
|
9
|
+
"lib/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
6
13
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"build:clean": "rimraf dist",
|
|
16
|
+
"prebuild": "npm run build:clean",
|
|
17
|
+
"postbuild": "echo 'TypeScript compilation complete. Output in ./dist/'",
|
|
18
|
+
"type-check": "tsc --noEmit",
|
|
19
|
+
"test": "npm run build && tape tests/**/*.js | faucet",
|
|
20
|
+
"test:compatibility": "npm run build && node test-compatibility.js",
|
|
21
|
+
"test:ci": "npm run test:coverage && npm run test:compatibility",
|
|
22
|
+
"test:coverage": "nyc npm test",
|
|
23
|
+
"test:coverage:report": "nyc report --reporter=html && echo '\nHTML coverage report generated in ./coverage/index.html'",
|
|
24
|
+
"test:coverage:ci": "nyc npm test && cat ./coverage/lcov.info",
|
|
25
|
+
"test:coverage:clean": "rimraf coverage .nyc_output",
|
|
26
|
+
"benchmark": "npm run build && node benchmark/run.js",
|
|
27
|
+
"clean": "npm run build:clean && npm run test:coverage:clean"
|
|
9
28
|
},
|
|
10
29
|
"repository": {
|
|
11
30
|
"type": "git",
|
|
@@ -14,12 +33,15 @@
|
|
|
14
33
|
"keywords": [
|
|
15
34
|
"simpleflake",
|
|
16
35
|
"snowflake",
|
|
36
|
+
"flake",
|
|
17
37
|
"id",
|
|
38
|
+
"uuidv4",
|
|
39
|
+
"uuidv7",
|
|
40
|
+
"database",
|
|
41
|
+
"shards",
|
|
42
|
+
"bigint",
|
|
18
43
|
"sql",
|
|
19
44
|
"nosql",
|
|
20
|
-
"flake",
|
|
21
|
-
"bigint",
|
|
22
|
-
"shards",
|
|
23
45
|
"partition"
|
|
24
46
|
],
|
|
25
47
|
"author": {
|
|
@@ -32,12 +54,17 @@
|
|
|
32
54
|
"url": "https://github.com/leodutra/simpleflakes/issues"
|
|
33
55
|
},
|
|
34
56
|
"homepage": "https://github.com/leodutra/simpleflakes#readme",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=16.0.0"
|
|
37
59
|
},
|
|
38
60
|
"devDependencies": {
|
|
61
|
+
"@types/node": "^24.3.1",
|
|
39
62
|
"benchmark": "^2.1.4",
|
|
40
|
-
"faucet": "^0.0.
|
|
41
|
-
"
|
|
63
|
+
"faucet": "^0.0.4",
|
|
64
|
+
"nyc": "^17.1.0",
|
|
65
|
+
"rimraf": "^6.0.1",
|
|
66
|
+
"tape": "^5.9.0",
|
|
67
|
+
"tsx": "^4.20.5",
|
|
68
|
+
"typescript": "^5.9.2"
|
|
42
69
|
}
|
|
43
70
|
}
|
package/.eslintrc.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
env: {
|
|
3
|
-
commonjs: true,
|
|
4
|
-
es6: true,
|
|
5
|
-
node: true,
|
|
6
|
-
},
|
|
7
|
-
extends: [
|
|
8
|
-
'airbnb-base',
|
|
9
|
-
],
|
|
10
|
-
globals: {
|
|
11
|
-
Atomics: 'readonly',
|
|
12
|
-
SharedArrayBuffer: 'readonly',
|
|
13
|
-
},
|
|
14
|
-
parserOptions: {
|
|
15
|
-
ecmaVersion: 2018,
|
|
16
|
-
},
|
|
17
|
-
rules: {
|
|
18
|
-
"comma-dangle": ["error", "never"]
|
|
19
|
-
},
|
|
20
|
-
};
|
package/.travis.yml
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
language: node_js
|
|
2
|
-
node_js:
|
|
3
|
-
- stable
|
|
4
|
-
- '12'
|
|
5
|
-
- '11'
|
|
6
|
-
- '10'
|
|
7
|
-
- '8'
|
|
8
|
-
|
|
9
|
-
before_install:
|
|
10
|
-
- npm install -g istanbul coveralls codacy-coverage
|
|
11
|
-
|
|
12
|
-
before_script:
|
|
13
|
-
- export CODACY_PROJECT_TOKEN=becf7b26a5d84fceab4c94d0bb2bf2ec
|
|
14
|
-
|
|
15
|
-
script: "istanbul cover ./node_modules/tape/bin/tape --report lcovonly -- tests/**/*.js && cat ./coverage/lcov.info | coveralls && cat ./coverage/lcov.info | codacy-coverage && rm -rf ./coverage"
|
|
16
|
-
|
|
17
|
-
deploy:
|
|
18
|
-
provider: npm
|
|
19
|
-
email: leodutra.br@gmail.com
|
|
20
|
-
api_key:
|
|
21
|
-
secure: HneFWS9YKoDkLyS5m2c8KMRnjGes1zIi3VnWX5rUuFVP/W+wybcLuyAtPbNzVhz7i7GbcKbIPLSP3lGaD4zBXg8Ds4WINBH09N1EKOrrtzt+A5SNaVHCm02rB8m992gNg0s19gVJD5/6MgJQ4+CJJTIKG3VNok3voZ8mwhZc5B6FKhlm4cU1VYJkm3ZiBeBUDxUlF77uaLIRlWjlibEwTf6Uz9rHhaDd0InlLoWwLOk136vU6QVDyh/84FhDUxytyLwi0WDnhlWQjFrsGB6oZA5MerG/udPMgKTG+pdhBRTt8QtkQqnDTmMPyQyBIe/TxOysGGKP3h7j/gz7yMhkDBCzI4xOcV25ch31kti9LjZPU0KQhJ0E2qjgOMxB1VrhxmzXAVuQKAgzsfeAKoz4xjM7BSBw4nmhdxZTGZWWDldKRcA4tu3EI30nhYaxxubim9CpPRAYK6G1bt3704Lx0XAMf5me7nxAxfzKgaD2CVKdOe3WNjnO7Nb9kSH2EYXP0Tsz8zFsqD4TRBoLs6GZpiD/tlNmoiPZ0/Bqaoh8NXvnjeOaVv2SZaZZ2Ndc0SrZS/8j6tHwhlddSAoi/IAWn5s72HUveGNKdDOxccEeeWm6s1cpxby0slTCjS5i7IyXcxlYV5k+iHmi0apf4dnc4faUgk6YM5aCvWT0yKSUI90=
|
|
22
|
-
on:
|
|
23
|
-
tags: true
|
|
24
|
-
repo: leodutra/simpleflakes
|
package/benchmark/run.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
-
const Benchmark = require('benchmark');
|
|
3
|
-
|
|
4
|
-
const suite = new Benchmark.Suite();
|
|
5
|
-
const legacy = require('../lib/simpleflakes-legacy');
|
|
6
|
-
const lib = require('../lib/simpleflakes');
|
|
7
|
-
|
|
8
|
-
const { BigNum } = legacy;
|
|
9
|
-
|
|
10
|
-
const SIMPLEFLAKE = '4242436206093260245';
|
|
11
|
-
const SIMPLEFLAKE_EPOCH = 946702800000;
|
|
12
|
-
const SIMPLEFLAKE_TIMESTAMP = 1452440606092;
|
|
13
|
-
const SIMPLEFLAKE_RANDOMBITS = 7460309;
|
|
14
|
-
|
|
15
|
-
suite.add('simpleflake()', () => {
|
|
16
|
-
lib.simpleflake();
|
|
17
|
-
})
|
|
18
|
-
.add('simpleflake(parameterization)', () => {
|
|
19
|
-
lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH);
|
|
20
|
-
})
|
|
21
|
-
.add('binary()', () => {
|
|
22
|
-
lib.binary(64);
|
|
23
|
-
})
|
|
24
|
-
.add('BigInt()', () => {
|
|
25
|
-
// eslint-disable-next-line no-undef
|
|
26
|
-
BigInt('4242436206093260245');
|
|
27
|
-
})
|
|
28
|
-
.add('parseSimpleflake()', () => {
|
|
29
|
-
lib.parseSimpleflake(SIMPLEFLAKE);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// legacy tests
|
|
34
|
-
suite.add('legacy simpleflake()', () => {
|
|
35
|
-
legacy.simpleflake();
|
|
36
|
-
})
|
|
37
|
-
.add('legacy simpleflake(parameterization)', () => {
|
|
38
|
-
legacy.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH);
|
|
39
|
-
})
|
|
40
|
-
.add('legacy binary()', () => {
|
|
41
|
-
legacy.binary(64);
|
|
42
|
-
})
|
|
43
|
-
.add('legacy new BigNum()', () => {
|
|
44
|
-
// eslint-disable-next-line no-new
|
|
45
|
-
new BigNum('4242436206093260245', 10);
|
|
46
|
-
})
|
|
47
|
-
.add('legacy parseSimpleflake()', () => {
|
|
48
|
-
legacy.parseSimpleflake(SIMPLEFLAKE);
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
// add listeners
|
|
52
|
-
.on('cycle', (event) => {
|
|
53
|
-
console.log(String(event.target));
|
|
54
|
-
})
|
|
55
|
-
// .on('complete', function() {
|
|
56
|
-
// console.log('Fastest is ' + this.filter('fastest').map('name'))
|
|
57
|
-
// })
|
|
58
|
-
// run async
|
|
59
|
-
.run({ async: true });
|
package/index.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
const BigNum = require('bn.js');
|
|
2
|
-
|
|
3
|
-
const SIMPLEFLAKE_EPOCH = 946684800000; // Date.UTC(2000, 0, 1) == epoch ms, since 1 Jan 2000 00:00
|
|
4
|
-
const SIMPLEFLAKE_EPOCH_BIGNUM = new BigNum(SIMPLEFLAKE_EPOCH, 10);
|
|
5
|
-
const UNSIGNED_23BIT_MAX = 8388607; // (Math.pow(2, 23) - 1) >> 0
|
|
6
|
-
|
|
7
|
-
const SIMPLEFLAKE_TIMESTAMP_LENGTH = 41;
|
|
8
|
-
const SIMPLEFLAKE_RANDOM_LENGTH = 23;
|
|
9
|
-
|
|
10
|
-
const SIMPLEFLAKE_RANDOM_SHIFT = 0;
|
|
11
|
-
const SIMPLEFLAKE_TIMESTAMP_SHIFT = 23;
|
|
12
|
-
|
|
13
|
-
const CACHE_64_BIT_ZEROS = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
14
|
-
const CACHE_64_BIT_ONES = '1111111111111111111111111111111111111111111111111111111111111111';
|
|
15
|
-
|
|
16
|
-
// cache
|
|
17
|
-
const dateNow = Date.now || function now() { return new Date().getTime(); };
|
|
18
|
-
|
|
19
|
-
function simpleflake(ts, randomBits, epoch) {
|
|
20
|
-
return new BigNum((ts || dateNow()) - (epoch == null ? SIMPLEFLAKE_EPOCH : epoch), 10)
|
|
21
|
-
.shln(23).add(new BigNum(randomBits || Math.round(Math.random() * UNSIGNED_23BIT_MAX), 10));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function binary(value, padding) {
|
|
25
|
-
const bignum = new BigNum(value, 10).toString(2);
|
|
26
|
-
return padding !== false && bignum.length < 64
|
|
27
|
-
? CACHE_64_BIT_ZEROS.substr(0, 64 - bignum.length) + bignum
|
|
28
|
-
: bignum;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function extractBits(data, shift, length) {
|
|
32
|
-
// return new BigNum(CACHE_64_BIT_ONES.substr(0, length), 2)
|
|
33
|
-
// .shln(shift).and(new BigNum(data, 10)).shrn(shift);
|
|
34
|
-
return (new BigNum(data, 10)).shrn(shift).and(new BigNum(CACHE_64_BIT_ONES.substr(0, length), 2));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function SimpleFlakeStruct(timestamp, randomBits) {
|
|
38
|
-
if (this instanceof SimpleFlakeStruct) {
|
|
39
|
-
if (timestamp == null || randomBits == null) {
|
|
40
|
-
throw new Error('Missing argument for SimpleFlakeStruct.');
|
|
41
|
-
}
|
|
42
|
-
this.timestamp = timestamp;
|
|
43
|
-
this.randomBits = randomBits;
|
|
44
|
-
} else {
|
|
45
|
-
return new SimpleFlakeStruct(timestamp, randomBits);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function parseSimpleflake(flake) {
|
|
50
|
-
return new SimpleFlakeStruct(
|
|
51
|
-
// timestamp
|
|
52
|
-
extractBits(flake, SIMPLEFLAKE_TIMESTAMP_SHIFT, SIMPLEFLAKE_TIMESTAMP_LENGTH)
|
|
53
|
-
.add(SIMPLEFLAKE_EPOCH_BIGNUM).toString(10),
|
|
54
|
-
// random bits
|
|
55
|
-
extractBits(flake, SIMPLEFLAKE_RANDOM_SHIFT, SIMPLEFLAKE_RANDOM_LENGTH).toString(10)
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
module.exports = {
|
|
60
|
-
// Enhancements
|
|
61
|
-
SimpleFlakeStruct,
|
|
62
|
-
|
|
63
|
-
// original API
|
|
64
|
-
simpleflakeStruct: SimpleFlakeStruct,
|
|
65
|
-
extractBits,
|
|
66
|
-
parseSimpleflake,
|
|
67
|
-
binary,
|
|
68
|
-
SIMPLEFLAKE_EPOCH,
|
|
69
|
-
simpleflake
|
|
70
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const test = require('tape');
|
|
4
|
-
const BigNum = require('bn.js');
|
|
5
|
-
const lib = require('../lib/simpleflakes-legacy');
|
|
6
|
-
|
|
7
|
-
const SIMPLEFLAKE = '4242436206093260245';
|
|
8
|
-
const SIMPLEFLAKE_EPOCH = 946702800000;
|
|
9
|
-
const SIMPLEFLAKE_TIMESTAMP = 1452440606092;
|
|
10
|
-
const SIMPLEFLAKE_RANDOMBITS = 7460309;
|
|
11
|
-
|
|
12
|
-
const SIMPLEFLAKE_2 = '11101011100000001010010100000010000110011100011101010111010101';
|
|
13
|
-
const SIMPLEFLAKE_16 = '3ae029408671d5d5';
|
|
14
|
-
const SIMPLEFLAKE_36 = 'w8cq4fjf37x1';
|
|
15
|
-
|
|
16
|
-
test('testing dependency bn.js', (t) => {
|
|
17
|
-
const bignum = new BigNum(SIMPLEFLAKE);
|
|
18
|
-
t.equal(bignum.toString(), SIMPLEFLAKE, 'bit number lib retrieves the right stored value?');
|
|
19
|
-
t.equal(bignum.toString(), bignum.toString(10), '<big number>.toString() aliases .toString(10)?');
|
|
20
|
-
t.equal(bignum.toString(2), SIMPLEFLAKE_2, 'big number as base 2?');
|
|
21
|
-
t.equal(bignum.toString(16), SIMPLEFLAKE_16, 'big number as base 16?');
|
|
22
|
-
t.equal(bignum.toString(36), SIMPLEFLAKE_36, 'big number as base 36?');
|
|
23
|
-
t.end();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('testing legacy simpleflake()', (t) => {
|
|
27
|
-
t.assert(lib.simpleflake() instanceof BigNum, 'returning correct instance of big number lib?');
|
|
28
|
-
t.equal(lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH).toString(), '4242436206093260245', 'right timestamp, random bits and epoch parameterization?');
|
|
29
|
-
t.end();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('testing legacy binary()', (t) => {
|
|
33
|
-
t.equal(lib.binary('83928382810918298'), '0000000100101010001011000110101101100100000001001000110110011010', 'valid simpleflake.binary(\'83928382810918298\') result?');
|
|
34
|
-
t.equal(lib.binary('83928382810918298', false), '100101010001011000110101101100100000001001000110110011010', 'valid simpleflake.binary(\'83928382810918298\', false) result?');
|
|
35
|
-
t.equal(lib.binary(7), '0000000000000000000000000000000000000000000000000000000000000111', 'valid simpleflake.binary(7) result?');
|
|
36
|
-
t.equal(lib.binary(7, false), '111', 'valid simpleflake.binary(7, false) result?');
|
|
37
|
-
t.equal(lib.binary(64), '0000000000000000000000000000000000000000000000000000000001000000', 'valid simpleflake.binary(64) result?');
|
|
38
|
-
t.equal(lib.binary(64, false), '1000000', 'valid simpleflake.binary(64, false) result?');
|
|
39
|
-
t.end();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('testing legacy extractBits()', (t) => {
|
|
43
|
-
t.assert(lib.extractBits(7, 0, 1) instanceof BigNum, 'returns big number object');
|
|
44
|
-
t.equal(lib.extractBits(7, 0, 1).toString(), '1', 'extractBits(7, 0, 1)');
|
|
45
|
-
t.equal(lib.extractBits(7, 0, 2).toString(), '3', 'extractBits(7, 0, 2)');
|
|
46
|
-
t.equal(lib.extractBits(7, 0, 3).toString(), '7', 'extractBits(7, 0, 3)');
|
|
47
|
-
t.equal(lib.extractBits(7, 1, 2).toString(), '3', 'extractBits(7, 1, 2)');
|
|
48
|
-
t.equal(lib.extractBits(7, 2, 1).toString(), '1', 'extractBits(7, 2, 1)');
|
|
49
|
-
t.equal(lib.extractBits(7, 2, 2).toString(), '1', 'extractBits(7, 2, 2)');
|
|
50
|
-
t.end();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('testing legacy SimpleFlakeStruct()', (t) => {
|
|
54
|
-
t.assert(lib.SimpleFlakeStruct(SIMPLEFLAKE_TIMESTAMP.toString(), SIMPLEFLAKE_RANDOMBITS.toString()) instanceof lib.SimpleFlakeStruct, 'returning new SimpleFlakeStruct() when calling SimpleFlakeStruct()?');
|
|
55
|
-
t.throws(() => {
|
|
56
|
-
let undef;
|
|
57
|
-
lib.SimpleFlakeStruct(undef, '1');
|
|
58
|
-
}, 'throw typeError when timestamp arg is missing');
|
|
59
|
-
|
|
60
|
-
t.throws(() => {
|
|
61
|
-
lib.SimpleFlakeStruct('1');
|
|
62
|
-
}, 'throw typeError when randomBits argument is missing');
|
|
63
|
-
|
|
64
|
-
t.throws(() => {
|
|
65
|
-
lib.SimpleFlakeStruct();
|
|
66
|
-
}, 'throw typeError when arguments are missing');
|
|
67
|
-
|
|
68
|
-
t.end();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('testing legacy parseSimpleflake()', (t) => {
|
|
72
|
-
const flake = lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS);
|
|
73
|
-
t.equal(lib.parseSimpleflake(flake).timestamp, SIMPLEFLAKE_TIMESTAMP.toString(), 'correct timestamp parsing?');
|
|
74
|
-
t.equal(lib.parseSimpleflake(flake).randomBits, SIMPLEFLAKE_RANDOMBITS.toString(), 'correct random bits parsing?');
|
|
75
|
-
t.end();
|
|
76
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
if (typeof BigInt === 'function') {
|
|
2
|
-
// eslint-disable-next-line global-require
|
|
3
|
-
const test = require('tape');
|
|
4
|
-
// eslint-disable-next-line global-require
|
|
5
|
-
const lib = require('../lib/simpleflakes');
|
|
6
|
-
const SIMPLEFLAKE_EPOCH = 946702800000;
|
|
7
|
-
const SIMPLEFLAKE_TIMESTAMP = 1452440606092;
|
|
8
|
-
const SIMPLEFLAKE_RANDOMBITS = 7460309;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
test('testing simpleflake()', (t) => {
|
|
12
|
-
// eslint-disable-next-line valid-typeof
|
|
13
|
-
t.assert(typeof lib.simpleflake() === 'bigint', 'returning BigInt?');
|
|
14
|
-
t.equal(lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS, SIMPLEFLAKE_EPOCH).toString(), '4242436206093260245', 'right timestamp, random bits and epoch parameterization?');
|
|
15
|
-
t.end();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('testing binary()', (t) => {
|
|
19
|
-
t.equal(lib.binary('83928382810918298'), '0000000100101010001011000110101101100100000001001000110110011010', "valid simpleflake.binary('83928382810918298') result?");
|
|
20
|
-
t.equal(lib.binary('83928382810918298', false), '100101010001011000110101101100100000001001000110110011010', "valid simpleflake.binary('83928382810918298', false) result?");
|
|
21
|
-
t.equal(lib.binary(7), '0000000000000000000000000000000000000000000000000000000000000111', 'valid simpleflake.binary(7) result?');
|
|
22
|
-
t.equal(lib.binary(7, false), '111', 'valid simpleflake.binary(7, false) result?');
|
|
23
|
-
t.equal(lib.binary(64), '0000000000000000000000000000000000000000000000000000000001000000', 'valid simpleflake.binary(64) result?');
|
|
24
|
-
t.equal(lib.binary(64, false), '1000000', 'valid simpleflake.binary(64, false) result?');
|
|
25
|
-
t.end();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
test('testing extractBits()', (t) => {
|
|
30
|
-
// eslint-disable-next-line valid-typeof
|
|
31
|
-
t.assert(typeof lib.extractBits(7, 0, 1) === 'bigint', 'returns big int');
|
|
32
|
-
t.equal(lib.extractBits(7, 0, 1).toString(), '1', 'extractBits(7, 0, 1)');
|
|
33
|
-
t.equal(lib.extractBits(7, 0, 2).toString(), '3', 'extractBits(7, 0, 2)');
|
|
34
|
-
t.equal(lib.extractBits(7, 0, 3).toString(), '7', 'extractBits(7, 0, 3)');
|
|
35
|
-
t.equal(lib.extractBits(7, 1, 2).toString(), '3', 'extractBits(7, 1, 2)');
|
|
36
|
-
t.equal(lib.extractBits(7, 2, 1).toString(), '1', 'extractBits(7, 2, 1)');
|
|
37
|
-
t.equal(lib.extractBits(7, 2, 2).toString(), '1', 'extractBits(7, 2, 2)');
|
|
38
|
-
t.end();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('testing SimpleFlakeStruct()', (t) => {
|
|
42
|
-
t.assert(lib.SimpleFlakeStruct(SIMPLEFLAKE_TIMESTAMP.toString(), SIMPLEFLAKE_RANDOMBITS.toString()) instanceof lib.SimpleFlakeStruct, 'returning new SimpleFlakeStruct() when calling SimpleFlakeStruct()?');
|
|
43
|
-
t.throws(() => {
|
|
44
|
-
let undef;
|
|
45
|
-
lib.SimpleFlakeStruct(undef, '1');
|
|
46
|
-
}, 'throw typeError when timestamp arg is missing');
|
|
47
|
-
|
|
48
|
-
t.throws(() => {
|
|
49
|
-
lib.SimpleFlakeStruct('1');
|
|
50
|
-
}, 'throw typeError when randomBits argument is missing');
|
|
51
|
-
|
|
52
|
-
t.throws(() => {
|
|
53
|
-
lib.SimpleFlakeStruct();
|
|
54
|
-
}, 'throw typeError when arguments are missing');
|
|
55
|
-
|
|
56
|
-
t.end();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test('testing parseSimpleflake()', (t) => {
|
|
60
|
-
const flake = lib.simpleflake(SIMPLEFLAKE_TIMESTAMP, SIMPLEFLAKE_RANDOMBITS);
|
|
61
|
-
t.equal(lib.parseSimpleflake(flake).timestamp, SIMPLEFLAKE_TIMESTAMP.toString(), 'correct timestamp parsing?');
|
|
62
|
-
t.equal(lib.parseSimpleflake(flake).randomBits, SIMPLEFLAKE_RANDOMBITS.toString(), 'correct random bits parsing?');
|
|
63
|
-
t.end();
|
|
64
|
-
});
|
|
65
|
-
}
|