Skip to content

Commit

Permalink
fix(ksuid): fix #403, update KSUID32 epoch handling
Browse files Browse the repository at this point in the history
- update .ensureTime() to check against optional max value
- fix int coercion in KSUID32.timeOnlyBinary()
- update readme
  • Loading branch information
postspectacular committed Aug 6, 2023
1 parent b7c1b03 commit abbfc5a
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 25 deletions.
25 changes: 13 additions & 12 deletions packages/ksuid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,22 @@ Idea based on [segmentio/ksuid](https://github.com/segmentio/ksuid), though the
added flexibility in terms of configuration & implementation also enables the
creation of [ULIDs](https://github.com/ulid/spec):

| Feature | KSUID default | ULID default |
|---------------------------------------|------------------------|------------------------|
| Configurable bit size | 160 bits | 128 bits |
| Base-N encoding scheme | base62<sup>(1)</sup> | base32 (Crockford) |
| Timestamp resolution | seconds (32 bits) | milliseconds (48 bits) |
| | milliseconds (64 bits) | |
| Epoch start time offset | approx. 2020-09-13 | none |
| Time-only base ID generation |||
| ID parsing / decomposition |||
| Configurable RNG source<sup>(2)</sup> |||
| Feature | KSUID default | ULID default |
|---------------------------------------|----------------------------------|------------------------|
| Configurable bit size | 160 bits | 128 bits |
| Base-N encoding scheme | base62<sup>(1)</sup> | base32 (Crockford) |
| Timestamp resolution | seconds (32 bits) | milliseconds (48 bits) |
| | milliseconds (64 bits) | |
| Epoch start time offset | approx. 2020-09-13<sup>(2)</sup> | none |
| Time-only base ID generation | ||
| ID parsing / decomposition | ||
| Configurable RNG source<sup>(3)</sup> | ||

- <sup>(1)</sup> See
[@thi.ng/base-n](https://github.com/thi-ng/umbrella/tree/develop/packages/base-n)
for alternatives
- <sup>(2)</sup> Default: `window.crypto`, `Math.random` as fallback
- <sup>(2)</sup> With the default offset, the max. supported date for `KSUID32` is 2156-10-20T18:54:55Z
- <sup>(3)</sup> Default: `window.crypto`, `Math.random` as fallback

IDs generated w/ this package are composed of a 32, 48 or 64 bit Unix epochs and
N additional bits of a random payload (from a configurable source). By default
Expand Down Expand Up @@ -110,7 +111,7 @@ For Node.js REPL:
const ksuid = await import("@thi.ng/ksuid");
```

Package sizes (brotli'd, pre-treeshake): ESM: 769 bytes
Package sizes (brotli'd, pre-treeshake): ESM: 809 bytes

## Dependencies

Expand Down
3 changes: 2 additions & 1 deletion packages/ksuid/src/aksuid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ export abstract class AKSUID implements IKSUID {
return buf;
}

protected ensureTime(t: number) {
protected ensureTime(t: number, max?: number) {
assert(t >= 0, "configured base epoch must be in the past");
max && assert(t <= max, `given epoch is out of range ([0...${max}])`);
return t;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/ksuid/src/ksuid32.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AKSUID } from "./aksuid.js";
import type { KSUIDOpts } from "./api.js";

const MAX_EPOCH = -1 >>> 0;

export class KSUID32 extends AKSUID {
constructor(opts?: Partial<KSUIDOpts>) {
super(4, {
Expand All @@ -12,7 +14,7 @@ export class KSUID32 extends AKSUID {

timeOnlyBinary(epoch = Date.now()) {
const buf = new Uint8Array(this.size);
const t = this.ensureTime(((epoch - this.epoch) / 1000) | 0);
const t = this.ensureTime((epoch - this.epoch) / 1000, MAX_EPOCH) >>> 0;
buf.set([t >>> 24, (t >> 16) & 0xff, (t >> 8) & 0xff, t & 0xff]);
return buf;
}
Expand Down
23 changes: 12 additions & 11 deletions packages/ksuid/tpl.readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@ Idea based on [segmentio/ksuid](https://github.com/segmentio/ksuid), though the
added flexibility in terms of configuration & implementation also enables the
creation of [ULIDs](https://github.com/ulid/spec):

| Feature | KSUID default | ULID default |
|---------------------------------------|------------------------|------------------------|
| Configurable bit size | 160 bits | 128 bits |
| Base-N encoding scheme | base62<sup>(1)</sup> | base32 (Crockford) |
| Timestamp resolution | seconds (32 bits) | milliseconds (48 bits) |
| | milliseconds (64 bits) | |
| Epoch start time offset | approx. 2020-09-13 | none |
| Time-only base ID generation |||
| ID parsing / decomposition |||
| Configurable RNG source<sup>(2)</sup> |||
| Feature | KSUID default | ULID default |
|---------------------------------------|----------------------------------|------------------------|
| Configurable bit size | 160 bits | 128 bits |
| Base-N encoding scheme | base62<sup>(1)</sup> | base32 (Crockford) |
| Timestamp resolution | seconds (32 bits) | milliseconds (48 bits) |
| | milliseconds (64 bits) | |
| Epoch start time offset | approx. 2020-09-13<sup>(2)</sup> | none |
| Time-only base ID generation | ||
| ID parsing / decomposition | ||
| Configurable RNG source<sup>(3)</sup> | ||

- <sup>(1)</sup> See
[@thi.ng/base-n](https://github.com/thi-ng/umbrella/tree/develop/packages/base-n)
for alternatives
- <sup>(2)</sup> Default: `window.crypto`, `Math.random` as fallback
- <sup>(2)</sup> With the default offset, the max. supported date for `KSUID32` is 2156-10-20T18:54:55Z
- <sup>(3)</sup> Default: `window.crypto`, `Math.random` as fallback

IDs generated w/ this package are composed of a 32, 48 or 64 bit Unix epochs and
N additional bits of a random payload (from a configurable source). By default
Expand Down

0 comments on commit abbfc5a

Please sign in to comment.