Skip to content

Commit

Permalink
πŸ› typeid-js: fix zero not being a valid time (#373)
Browse files Browse the repository at this point in the history
Greetings @jetify-com Team, πŸ‘‹

when running some of my unit tests using time mocking I discovered that
a time of `0` currently spawns a `RangeError` in `uuidv7` even tho it's
a perfectly valid time. This special case will most likely not occur in
production, nevertheless being able to test with mocked time starting
from timestamp zero is very convenient. As all data is usually
initialized at the beginning of a every test, this would otherwise
require initializing system time to some arbitrary value, which sounds
more like a workaround than a solution. As this is a limitation of the
`uuidv7` library I proposed a fix to @LiosK that would lift this
limitation without impacting performance or handling:
LiosK/uuidv7#14 (comment) Sadly he
is not interested in lifting this limitation and won't merge the fix.

This PR aims to fix this issue on your end by migrating from
https://github.com/LiosK/uuidv7 to https://github.com/uuidjs/uuid which
seems to be more widely adopted and better maintained anyway. I also
tested performance and found it to be marginally better.

For a a quick reproduction of the issue checkout:
https://github.com/lukas-runge/typeid-zero-not-being-a-valid-time πŸ™Œ

Best regards,
@lukas-runge
  • Loading branch information
lukas-runge authored Sep 10, 2024
1 parent 08bf222 commit 1edfc67
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 29 deletions.
2 changes: 1 addition & 1 deletion typeid/typeid-js/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const config: JestConfigWithTsJest = {
},
],
},
transformIgnorePatterns: ["node_modules/(?!(.pnpm|uuidv7))"],
transformIgnorePatterns: ["node_modules/(?!(.pnpm|uuid))"],
verbose: true,
};

Expand Down
3 changes: 2 additions & 1 deletion typeid/typeid-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@
"@jest/globals": "^29.5.0",
"@tsconfig/strictest": "^2.0.1",
"@types/node": "^20.2.5",
"@types/uuid": "^10.0.0",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"tsup": "^6.7.0",
"typescript": "^5.0.4"
},
"dependencies": {
"uuidv7": "^0.6.2"
"uuid": "^10.0.0"
}
}
20 changes: 14 additions & 6 deletions typeid/typeid-js/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions typeid/typeid-js/src/typeid.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UUID } from "uuidv7";
import { stringify } from "uuid";
import { parseUUID } from "./parse_uuid";
import { encode, decode } from "./base32";
import {
Expand Down Expand Up @@ -39,8 +39,7 @@ export class TypeID<const T extends string> {
}

public toUUID(): string {
const uuid = UUID.ofInner(this.toUUIDBytes());
return uuid.toString();
return stringify(this.toUUIDBytes());
}

public toString(): `${T}_${string}` | string {
Expand Down
11 changes: 5 additions & 6 deletions typeid/typeid-js/src/unboxed/typeid.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { uuidv7obj, UUID } from "uuidv7";
import { stringify, v7 } from "uuid";
import { parseUUID } from "../parse_uuid";
import { encode, decode } from "../base32";
import { isValidPrefix } from "../prefix";
Expand All @@ -17,8 +17,9 @@ export function typeidUnboxed<T extends string>(
if (suffix) {
finalSuffix = suffix;
} else {
const uuid = uuidv7obj();
finalSuffix = encode(uuid.bytes);
const buffer = new Uint8Array(16);
v7(undefined, buffer);
finalSuffix = encode(buffer);
}

if (finalSuffix.length !== 26) {
Expand Down Expand Up @@ -151,9 +152,7 @@ export function toUUIDBytes<T extends string>(typeId: TypeId<T>): Uint8Array {
}

export function toUUID<T extends string>(typeId: TypeId<T>) {
const uuidBytes = toUUIDBytes(typeId);
const uuid = UUID.ofInner(uuidBytes);
return uuid.toString();
return stringify(toUUIDBytes(typeId));
}

export function fromUUIDBytes(
Expand Down
22 changes: 11 additions & 11 deletions typeid/typeid-js/test/valid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,27 @@ export default [
},
{
name: "one",
typeid: "00000000000000000000000001",
typeid: "0000000000e008000000000001",
prefix: "",
uuid: "00000000-0000-0000-0000-000000000001",
uuid: "00000000-0000-7000-8000-000000000001",
},
{
name: "ten",
typeid: "0000000000000000000000000a",
typeid: "0000000000e00900000000000a",
prefix: "",
uuid: "00000000-0000-0000-0000-00000000000a",
uuid: "00000000-0000-7000-9000-00000000000a",
},
{
name: "sixteen",
typeid: "0000000000000000000000000g",
typeid: "0000000000e00a00000000000g",
prefix: "",
uuid: "00000000-0000-0000-0000-000000000010",
uuid: "00000000-0000-7000-a000-000000000010",
},
{
name: "thirty-two",
typeid: "00000000000000000000000010",
typeid: "0000000000e00b000000000010",
prefix: "",
uuid: "00000000-0000-0000-0000-000000000020",
uuid: "00000000-0000-7000-b000-000000000020",
},
{
name: "max-valid",
Expand All @@ -46,10 +46,10 @@ export default [
uuid: "ffffffff-ffff-ffff-ffff-ffffffffffff",
},
{
name: "valid-alphabet",
typeid: "prefix_0123456789abcdefghjkmnpqrs",
name: "valid-alphabet-like",
typeid: "prefix_0123456789abcbefghjkmnpqrs",
prefix: "prefix",
uuid: "0110c853-1d09-52d8-d73e-1194e95b5f19",
uuid: "0110c853-1d09-52d8-b73e-1194e95b5f19",
},
{
name: "valid-uuidv7",
Expand Down
1 change: 0 additions & 1 deletion typeid/typeid-js/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ import { defineConfig } from "tsup";

export default defineConfig({
entry: ["./src/index.ts"],
noExternal: ["uuidv7"],
sourcemap: true,
});

0 comments on commit 1edfc67

Please sign in to comment.