@thi.ng/ksuid 3.1.15 → 3.2.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/CHANGELOG.md +17 -1
- package/README.md +14 -30
- package/aksuid.d.ts +4 -3
- package/aksuid.js +8 -7
- package/api.d.ts +13 -6
- package/ksuid32.d.ts +1 -1
- package/ksuid32.js +7 -4
- package/ksuid64.d.ts +1 -1
- package/ksuid64.js +11 -13
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2023-08-
|
|
3
|
+
- **Last updated**: 2023-08-12T13:14:08Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,22 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
## [3.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/ksuid@3.2.0) (2023-08-12)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- add optional buffer args for various methods ([def0db4](https://github.com/thi-ng/umbrella/commit/def0db4))
|
|
17
|
+
- update IKSUID interface
|
|
18
|
+
- update AKSUID to re-use internal byte buffer for string IDs,
|
|
19
|
+
avoiding allocating new temp arrays
|
|
20
|
+
- refactor .timeOnlyBinary() to avoid internal temp array
|
|
21
|
+
- update tests (re-ordered random bytes, due to [770dbe5d8](https://github.com/thi-ng/umbrella/commit/770dbe5d8))
|
|
22
|
+
|
|
23
|
+
#### ⏱ Performance improvements
|
|
24
|
+
|
|
25
|
+
- update .parse() ([da6765d](https://github.com/thi-ng/umbrella/commit/da6765d))
|
|
26
|
+
- avoid allocation
|
|
27
|
+
|
|
12
28
|
### [3.1.15](https://github.com/thi-ng/umbrella/tree/@thi.ng/ksuid@3.1.15) (2023-08-06)
|
|
13
29
|
|
|
14
30
|
#### 🩹 Bug fixes
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<!-- This file is generated - DO NOT EDIT! -->
|
|
2
|
+
<!-- Please see: https://github.com/thi-ng/umbrella/blob/develop/CONTRIBUTING.md#changes-to-readme-files -->
|
|
2
3
|
|
|
3
|
-
# 
|
|
4
5
|
|
|
5
6
|
[](https://www.npmjs.com/package/@thi.ng/ksuid)
|
|
6
7
|

|
|
@@ -87,7 +88,7 @@ implementations already used milliseconds.
|
|
|
87
88
|
|
|
88
89
|
## Related packages
|
|
89
90
|
|
|
90
|
-
- [@thi.ng/base-n](https://github.com/thi-ng/umbrella/tree/develop/packages/base-n) - Arbitrary base-n conversions w/ presets for
|
|
91
|
+
- [@thi.ng/base-n](https://github.com/thi-ng/umbrella/tree/develop/packages/base-n) - Arbitrary base-n conversions w/ presets for base8/16/32/36/58/62/64/85, support for bigints and encoding/decoding of byte arrays
|
|
91
92
|
- [@thi.ng/idgen](https://github.com/thi-ng/umbrella/tree/develop/packages/idgen) - Generator of opaque numeric identifiers with optional support for ID versioning and efficient re-use
|
|
92
93
|
- [@thi.ng/random](https://github.com/thi-ng/umbrella/tree/develop/packages/random) - Pseudo-random number generators w/ unified API, distributions, weighted choices, ID generation
|
|
93
94
|
|
|
@@ -111,7 +112,7 @@ For Node.js REPL:
|
|
|
111
112
|
const ksuid = await import("@thi.ng/ksuid");
|
|
112
113
|
```
|
|
113
114
|
|
|
114
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
115
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 888 bytes
|
|
115
116
|
|
|
116
117
|
## Dependencies
|
|
117
118
|
|
|
@@ -168,40 +169,23 @@ Creating custom IDs:
|
|
|
168
169
|
```ts
|
|
169
170
|
import { BASE36 } from "@thi.ng/base-n";
|
|
170
171
|
|
|
171
|
-
// no time shift, 64bit random
|
|
172
|
+
// using base36, no time shift, 64bit random part
|
|
172
173
|
const id36 = defKSUID32({ base: BASE36, epoch: 0, bytes: 8 });
|
|
173
174
|
|
|
174
|
-
|
|
175
|
+
id36.next();
|
|
175
176
|
// '2VOUKH4K59AG0RXR4XH'
|
|
176
177
|
```
|
|
177
178
|
|
|
178
179
|
## Benchmarks
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
q1: 62.64ms, q3: 64.41ms
|
|
189
|
-
sd: 6.93%
|
|
190
|
-
benchmarking: b62, 64bit, n=10000
|
|
191
|
-
warmup... 363.35ms (10 runs)
|
|
192
|
-
executing...
|
|
193
|
-
total: 3469.28ms, runs: 100
|
|
194
|
-
mean: 34.69ms, median: 34.41ms, range: [32.61..56.58]
|
|
195
|
-
q1: 33.35ms, q3: 35.41ms
|
|
196
|
-
sd: 7.47%
|
|
197
|
-
benchmarking: b62, 32bit, n=10000
|
|
198
|
-
warmup... 218.78ms (10 runs)
|
|
199
|
-
executing...
|
|
200
|
-
total: 2118.93ms, runs: 100
|
|
201
|
-
mean: 21.19ms, median: 20.95ms, range: [20.20..25.74]
|
|
202
|
-
q1: 20.71ms, q3: 21.30ms
|
|
203
|
-
sd: 4.14%
|
|
204
|
-
```
|
|
181
|
+
Benchmarks can be run via `yarn bench`. All timings in milliseconds (test
|
|
182
|
+
config: Node v20.4.0, MBA M1 2021, 16GB). The benchmark collects N KSUIDs w/
|
|
183
|
+
different configs in an array, with each case being run 100 times.
|
|
184
|
+
|
|
185
|
+
| Title| Iter| Size| Total| Mean| Median| Min| Max| Q1| Q3| SD%|
|
|
186
|
+
|------------------------|-------:|-------:|-----------:|-------:|-------:|-------:|-------:|-------:|-------:|-------:|
|
|
187
|
+
| b62, 128bit, n=10000| 100| 1| 2158.68| 21.59| 21.57| 19.91| 25.91| 20.42| 21.87| 6.26|
|
|
188
|
+
| b62, 64bit, n=10000| 100| 1| 1200.40| 12.00| 11.95| 11.27| 14.66| 11.82| 12.10| 3.99|
|
|
205
189
|
|
|
206
190
|
## Authors
|
|
207
191
|
|
package/aksuid.d.ts
CHANGED
|
@@ -11,15 +11,16 @@ export declare abstract class AKSUID implements IKSUID {
|
|
|
11
11
|
readonly encodedSize: number;
|
|
12
12
|
readonly base: BaseN;
|
|
13
13
|
readonly epoch: number;
|
|
14
|
+
protected tmp: Uint8Array;
|
|
14
15
|
protected rnd?: IRandom;
|
|
15
16
|
protected pad: (x: any) => string;
|
|
16
17
|
protected constructor(epochSize: number, opts: Partial<KSUIDOpts>);
|
|
17
18
|
next(): string;
|
|
18
|
-
nextBinary(): Uint8Array;
|
|
19
|
+
nextBinary(buf?: Uint8Array): Uint8Array;
|
|
19
20
|
timeOnly(epoch?: number): string;
|
|
20
|
-
abstract timeOnlyBinary(epoch?: number): Uint8Array;
|
|
21
|
+
abstract timeOnlyBinary(epoch?: number, buf?: Uint8Array): Uint8Array;
|
|
21
22
|
fromEpoch(epoch?: number): string;
|
|
22
|
-
fromEpochBinary(epoch?: number): Uint8Array;
|
|
23
|
+
fromEpochBinary(epoch?: number, buf?: Uint8Array): Uint8Array;
|
|
23
24
|
format(buf: Uint8Array): string;
|
|
24
25
|
abstract parse(id: string): {
|
|
25
26
|
epoch: number;
|
package/aksuid.js
CHANGED
|
@@ -15,24 +15,25 @@ export class AKSUID {
|
|
|
15
15
|
this.size = this.epochSize + opts.bytes;
|
|
16
16
|
this.encodedSize = this.base.size(2 ** (this.size * 8) - 1);
|
|
17
17
|
this.pad = padLeft(this.encodedSize, this.base.base[0]);
|
|
18
|
+
this.tmp = new Uint8Array(this.size);
|
|
18
19
|
}
|
|
19
20
|
next() {
|
|
20
|
-
return this.format(this.nextBinary());
|
|
21
|
+
return this.format(this.nextBinary(this.tmp));
|
|
21
22
|
}
|
|
22
|
-
nextBinary() {
|
|
23
|
-
|
|
23
|
+
nextBinary(buf) {
|
|
24
|
+
buf = this.timeOnlyBinary(undefined, buf);
|
|
24
25
|
return this.rnd
|
|
25
26
|
? randomBytesFrom(this.rnd, buf, this.epochSize)
|
|
26
27
|
: randomBytes(buf, this.epochSize);
|
|
27
28
|
}
|
|
28
29
|
timeOnly(epoch) {
|
|
29
|
-
return this.format(this.timeOnlyBinary(epoch));
|
|
30
|
+
return this.format(this.timeOnlyBinary(epoch, this.tmp.fill(0, this.epochSize)));
|
|
30
31
|
}
|
|
31
32
|
fromEpoch(epoch) {
|
|
32
|
-
return this.format(this.fromEpochBinary(epoch));
|
|
33
|
+
return this.format(this.fromEpochBinary(epoch, this.tmp));
|
|
33
34
|
}
|
|
34
|
-
fromEpochBinary(epoch) {
|
|
35
|
-
|
|
35
|
+
fromEpochBinary(epoch, buf) {
|
|
36
|
+
buf = this.timeOnlyBinary(epoch, buf);
|
|
36
37
|
return this.rnd
|
|
37
38
|
? randomBytesFrom(this.rnd, buf, this.epochSize)
|
|
38
39
|
: randomBytes(buf, this.epochSize);
|
package/api.d.ts
CHANGED
|
@@ -15,9 +15,12 @@ export interface IKSUID {
|
|
|
15
15
|
*/
|
|
16
16
|
next(): string;
|
|
17
17
|
/**
|
|
18
|
-
* Returns a new ID as byte array.
|
|
18
|
+
* Returns a new ID as byte array. If `buf` is given, writes result in
|
|
19
|
+
* there, else creates new byte array.
|
|
20
|
+
*
|
|
21
|
+
* @param buf
|
|
19
22
|
*/
|
|
20
|
-
nextBinary(): Uint8Array;
|
|
23
|
+
nextBinary(buf?: Uint8Array): Uint8Array;
|
|
21
24
|
/**
|
|
22
25
|
* Returns a new baseN encoded ID string for given `epoch` (default: current
|
|
23
26
|
* time) and with all random payload bytes set to 0.
|
|
@@ -27,11 +30,13 @@ export interface IKSUID {
|
|
|
27
30
|
timeOnly(epoch?: number): string;
|
|
28
31
|
/**
|
|
29
32
|
* Binary version of {@link KSUI.timeOnly}, but returns byte array. The
|
|
30
|
-
* first `epochSize` bytes will contain the timestamp.
|
|
33
|
+
* first `epochSize` bytes will contain the timestamp. If `buf` is given,
|
|
34
|
+
* writes result in there, else creates new byte array.
|
|
31
35
|
*
|
|
32
36
|
* @param epoch -
|
|
37
|
+
* @param buf -
|
|
33
38
|
*/
|
|
34
|
-
timeOnlyBinary(epoch?: number): Uint8Array;
|
|
39
|
+
timeOnlyBinary(epoch?: number, buf?: Uint8Array): Uint8Array;
|
|
35
40
|
/**
|
|
36
41
|
* Returns a new formatted ID, composed from user supplied timestamp
|
|
37
42
|
* (default: current time) and a random payload.
|
|
@@ -41,11 +46,13 @@ export interface IKSUID {
|
|
|
41
46
|
fromEpoch(epoch?: number): string;
|
|
42
47
|
/**
|
|
43
48
|
* Returns a new ID as byte array, composed from user supplied timestamp
|
|
44
|
-
* (default: current time) and a random payload.
|
|
49
|
+
* (default: current time) and a random payload. If `buf` is given, writes
|
|
50
|
+
* result in there, else creates new byte array.
|
|
45
51
|
*
|
|
46
52
|
* @param epoch
|
|
53
|
+
* @param buf
|
|
47
54
|
*/
|
|
48
|
-
fromEpochBinary(epoch?: number): Uint8Array;
|
|
55
|
+
fromEpochBinary(epoch?: number, buf?: Uint8Array): Uint8Array;
|
|
49
56
|
/**
|
|
50
57
|
* Returns baseN encoded version of given binary ID (generated via
|
|
51
58
|
* `.nextBinary()`).
|
package/ksuid32.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { AKSUID } from "./aksuid.js";
|
|
|
2
2
|
import type { KSUIDOpts } from "./api.js";
|
|
3
3
|
export declare class KSUID32 extends AKSUID {
|
|
4
4
|
constructor(opts?: Partial<KSUIDOpts>);
|
|
5
|
-
timeOnlyBinary(epoch?: number): Uint8Array;
|
|
5
|
+
timeOnlyBinary(epoch?: number, buf?: Uint8Array): Uint8Array;
|
|
6
6
|
parse(id: string): {
|
|
7
7
|
epoch: number;
|
|
8
8
|
id: Uint8Array;
|
package/ksuid32.js
CHANGED
|
@@ -8,14 +8,17 @@ export class KSUID32 extends AKSUID {
|
|
|
8
8
|
...opts,
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
|
-
timeOnlyBinary(epoch = Date.now()) {
|
|
12
|
-
|
|
11
|
+
timeOnlyBinary(epoch = Date.now(), buf) {
|
|
12
|
+
buf = buf || new Uint8Array(this.size);
|
|
13
13
|
const t = this.ensureTime((epoch - this.epoch) / 1000, MAX_EPOCH) >>> 0;
|
|
14
|
-
buf
|
|
14
|
+
buf[0] = t >>> 24;
|
|
15
|
+
buf[1] = (t >> 16) & 0xff;
|
|
16
|
+
buf[2] = (t >> 8) & 0xff;
|
|
17
|
+
buf[3] = t & 0xff;
|
|
15
18
|
return buf;
|
|
16
19
|
}
|
|
17
20
|
parse(id) {
|
|
18
|
-
const buf =
|
|
21
|
+
const buf = this.tmp;
|
|
19
22
|
this.base.decodeBytes(id, buf);
|
|
20
23
|
return {
|
|
21
24
|
epoch: this.u32(buf) * 1000 + this.epoch,
|
package/ksuid64.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { AKSUID } from "./aksuid.js";
|
|
|
2
2
|
import type { KSUIDOpts } from "./api.js";
|
|
3
3
|
export declare class KSUID64 extends AKSUID {
|
|
4
4
|
constructor(opts?: Partial<KSUIDOpts>);
|
|
5
|
-
timeOnlyBinary(epoch?: number): Uint8Array;
|
|
5
|
+
timeOnlyBinary(epoch?: number, buf?: Uint8Array): Uint8Array;
|
|
6
6
|
parse(id: string): {
|
|
7
7
|
epoch: number;
|
|
8
8
|
id: Uint8Array;
|
package/ksuid64.js
CHANGED
|
@@ -7,25 +7,23 @@ export class KSUID64 extends AKSUID {
|
|
|
7
7
|
...opts,
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
|
-
timeOnlyBinary(epoch = Date.now()) {
|
|
11
|
-
|
|
10
|
+
timeOnlyBinary(epoch = Date.now(), buf) {
|
|
11
|
+
buf = buf || new Uint8Array(this.size);
|
|
12
12
|
const t = this.ensureTime(epoch - this.epoch);
|
|
13
13
|
const h = (t / 4294967296) >>> 0;
|
|
14
14
|
const l = (t & 4294967295) >>> 0;
|
|
15
|
-
buf
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
l & 0xff,
|
|
24
|
-
]);
|
|
15
|
+
buf[0] = h >>> 24;
|
|
16
|
+
buf[1] = (h >> 16) & 0xff;
|
|
17
|
+
buf[2] = (h >> 8) & 0xff;
|
|
18
|
+
buf[3] = h & 0xff;
|
|
19
|
+
buf[4] = l >>> 24;
|
|
20
|
+
buf[5] = (l >> 16) & 0xff;
|
|
21
|
+
buf[6] = (l >> 8) & 0xff;
|
|
22
|
+
buf[7] = l & 0xff;
|
|
25
23
|
return buf;
|
|
26
24
|
}
|
|
27
25
|
parse(id) {
|
|
28
|
-
const buf =
|
|
26
|
+
const buf = this.tmp;
|
|
29
27
|
this.base.decodeBytes(id, buf);
|
|
30
28
|
return {
|
|
31
29
|
epoch: this.u32(buf) * 4294967296 + this.u32(buf, 4) + this.epoch,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/ksuid",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Configurable K-sortable unique IDs, ULIDs, binary & base-N encoded, 32/48/64bit time resolutions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
"test": "testament test"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@thi.ng/base-n": "^2.5.
|
|
40
|
-
"@thi.ng/errors": "^2.3.
|
|
41
|
-
"@thi.ng/random": "^3.
|
|
42
|
-
"@thi.ng/strings": "^3.4.
|
|
39
|
+
"@thi.ng/base-n": "^2.5.10",
|
|
40
|
+
"@thi.ng/errors": "^2.3.3",
|
|
41
|
+
"@thi.ng/random": "^3.6.0",
|
|
42
|
+
"@thi.ng/strings": "^3.4.11"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@microsoft/api-extractor": "^7.36.
|
|
46
|
-
"@thi.ng/testament": "^0.3.
|
|
45
|
+
"@microsoft/api-extractor": "^7.36.4",
|
|
46
|
+
"@thi.ng/testament": "^0.3.21",
|
|
47
47
|
"rimraf": "^5.0.1",
|
|
48
48
|
"tools": "^0.0.1",
|
|
49
49
|
"typedoc": "^0.24.8",
|
|
@@ -114,5 +114,5 @@
|
|
|
114
114
|
"status": "stable",
|
|
115
115
|
"year": 2020
|
|
116
116
|
},
|
|
117
|
-
"gitHead": "
|
|
117
|
+
"gitHead": "399f8c53d66b9b763d16c21bb59f145df5f59514\n"
|
|
118
118
|
}
|