Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@
"node": "./dist-cjs/submodules/event-streams/index.js",
"import": "./dist-es/submodules/event-streams/index.js",
"require": "./dist-cjs/submodules/event-streams/index.js"
},
"./uuid": {
"types": "./dist-types/submodules/uuid/index.d.ts",
"module": "./dist-es/submodules/uuid/index.js",
"node": "./dist-cjs/submodules/uuid/index.js",
"import": "./dist-es/submodules/uuid/index.js",
"require": "./dist-cjs/submodules/uuid/index.js"
}
},
"author": {
Expand Down Expand Up @@ -110,6 +117,8 @@
"./schema.js",
"./serde.d.ts",
"./serde.js",
"./uuid.d.ts",
"./uuid.js",
"dist-*/**"
],
"homepage": "https://github.com/smithy-lang/smithy-typescript/tree/main/packages/core",
Expand All @@ -127,6 +136,10 @@
"rimraf": "3.0.2",
"typedoc": "0.23.23"
},
"browser": {
"./dist-es/submodules/uuid/randomUUID": "./dist-es/submodules/uuid/randomUUID.browser"
},
"react-native": {},
"typedoc": {
"entryPoint": "src/index.ts"
},
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/submodules/uuid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./v4";
1 change: 1 addition & 0 deletions packages/core/src/submodules/uuid/randomUUID.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
2 changes: 2 additions & 0 deletions packages/core/src/submodules/uuid/randomUUID.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// If user has provided their polyfill, like "react-native-random-uuid"
export const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
4 changes: 4 additions & 0 deletions packages/core/src/submodules/uuid/randomUUID.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// ToDo: Merge Node.js and browser implementations after dropping support for Node.js 22.x
import crypto from "crypto";

export const randomUUID = crypto.randomUUID.bind(crypto);
46 changes: 46 additions & 0 deletions packages/core/src/submodules/uuid/v4.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { getRandomValues } from "crypto";
import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest";

describe("randomUUID", () => {
afterEach(() => {
vi.resetModules();
});

it("should call native randomUUID when available", async () => {
const mockUUID = "mocked-uuid";
const nativeRandomUUID = vi.fn(() => mockUUID);
vi.doMock("./randomUUID", () => ({ randomUUID: nativeRandomUUID }));

const { v4 } = await import("./v4");
const uuid = v4();

expect(nativeRandomUUID).toHaveBeenCalled();
expect(uuid).toBe(mockUUID);
});

describe("when native randomUUID is not available", () => {
let v4: any;
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

beforeEach(async () => {
vi.doMock("./randomUUID", () => ({ randomUUID: undefined }));
v4 = (await import("./v4")).v4;

// Simulate crypto.getRandomValues in test, as it's expected to be available
global.crypto = {
getRandomValues: getRandomValues,
} as any;
});

it("each generation is unique and matches regex", () => {
const uuids = new Set();
const iterations = 10_000;
for (let i = 0; i < iterations; i++) {
const uuid = v4();
expect(uuid).toMatch(UUID_REGEX);
uuids.add(uuid);
}
expect(uuids.size).toBe(iterations);
});
});
});
19 changes: 19 additions & 0 deletions packages/core/src/submodules/uuid/v4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { randomUUID } from "./randomUUID";

export const v4 = () => {
if (randomUUID) {
return randomUUID();
}

const rnds = new Uint8Array(16);
crypto.getRandomValues(rnds);

// Set version (4) and variant (RFC4122)
rnds[6] = (rnds[6] & 0x0f) | 0x40; // version 4
rnds[8] = (rnds[8] & 0x3f) | 0x80; // variant

return Array.from(rnds.slice(0, 16))
.map((b) => b.toString(16).padStart(2, "0"))
.join("")
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5");
};
3 changes: 2 additions & 1 deletion packages/core/tsconfig.cjs.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"@smithy/core/protocols": ["./src/submodules/protocols/index.ts"],
"@smithy/core/serde": ["./src/submodules/serde/index.ts"],
"@smithy/core/schema": ["./src/submodules/schema/index.ts"],
"@smithy/core/event-streams": ["./src/submodules/event-streams/index.ts"]
"@smithy/core/event-streams": ["./src/submodules/event-streams/index.ts"],
"@smithy/core/uuid": ["./src/submodules/uuid/index.ts"]
}
},
"extends": "../../tsconfig.cjs.json",
Expand Down
3 changes: 2 additions & 1 deletion packages/core/tsconfig.es.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"@smithy/core/protocols": ["./src/submodules/protocols/index.ts"],
"@smithy/core/serde": ["./src/submodules/serde/index.ts"],
"@smithy/core/schema": ["./src/submodules/schema/index.ts"],
"@smithy/core/event-streams": ["./src/submodules/event-streams/index.ts"]
"@smithy/core/event-streams": ["./src/submodules/event-streams/index.ts"],
"@smithy/core/uuid": ["./src/submodules/uuid/index.ts"]
}
},
"extends": "../../tsconfig.es.json",
Expand Down
3 changes: 2 additions & 1 deletion packages/core/tsconfig.types.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"@smithy/core/protocols": ["./src/submodules/protocols/index.ts"],
"@smithy/core/serde": ["./src/submodules/serde/index.ts"],
"@smithy/core/schema": ["./src/submodules/schema/index.ts"],
"@smithy/core/event-streams": ["./src/submodules/event-streams/index.ts"]
"@smithy/core/event-streams": ["./src/submodules/event-streams/index.ts"],
"@smithy/core/uuid": ["./src/submodules/uuid/index.ts"]
}
},
"extends": "../../tsconfig.types.json",
Expand Down
7 changes: 7 additions & 0 deletions packages/core/uuid.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Do not edit:
* This is a compatibility redirect for contexts that do not understand package.json exports field.
*/
declare module "@smithy/core/uuid" {
export * from "@smithy/core/dist-types/submodules/uuid/index.d";
}
6 changes: 6 additions & 0 deletions packages/core/uuid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

/**
* Do not edit:
* This is a compatibility redirect for contexts that do not understand package.json exports field.
*/
module.exports = require("./dist-cjs/submodules/uuid/index.js");
Loading