Skip to content

feat: replace uuid.v4 with crypto.randomUUID() #1657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ public enum TypeScriptDependency implements Dependency {

NODE_CONFIG_PROVIDER("dependencies", "@smithy/node-config-provider", false),

/**
* @deprecated use crypto.randomUUID().
*/
@Deprecated
UUID_TYPES("dependencies", "@types/uuid", "^9.0.1", false),
@Deprecated
UUID("dependencies", "uuid", "^9.0.1", false),

// Conditionally added when httpChecksumRequired trait exists
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -873,13 +873,8 @@ private void writeRequestQueryParam(
Shape target = model.expectShape(binding.getMember().getTarget());

boolean isIdempotencyToken = binding.getMember().hasTrait(IdempotencyTokenTrait.class);
if (isIdempotencyToken) {
writer
.addDependency(TypeScriptDependency.UUID_TYPES)
.addImport("v4", "generateIdempotencyToken", TypeScriptDependency.UUID);
}
boolean isRequired = binding.getMember().isRequired();
String idempotencyComponent = (isIdempotencyToken && !isRequired) ? " ?? generateIdempotencyToken()" : "";
String idempotencyComponent = (isIdempotencyToken && !isRequired) ? " ?? crypto.randomUUID()" : "";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is runtime agnostic file, and crypto is not available globally the minimum version of Node.js, i.e. 18.0.0, as per my tests

$ nvm use 18.0.0
Now using node v18.0.0 (npm v8.6.0)

$ cat randomUUID.mjs 
console.log(crypto.randomUUID());

$ node randomUUID.mjs 
file:///Users/trivikr/workspace/test/randomUUID.mjs:1
console.log(crypto.randomUUID());
            ^

ReferenceError: crypto is not defined
    at file:///Users/trivikr/workspace/test/randomUUID.mjs:1:13
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    at async loadESM (node:internal/process/esm_loader:85:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

Node.js v18.0.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crypto was added globally as follows:

  • v23.0.0 | No longer experimental.
  • v19.0.0 | No longer behind --experimental-global-webcrypto CLI flag.
  • v17.6.0, v16.15.0 |  Added in: v17.6.0, v16.15.0

Docs: https://nodejs.org/api/globals.html#crypto

Copy link
Contributor

@trivikr trivikr Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can replace uuid with a utility in core though, where Node.js one will get it from crypto.
That utility can be removed once we drop support for Node.js 22.x

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there something blocking us from simply importing crypto module the old way? randomUUID() method in node:crypto module was added in Node.js v15.6.0, v14.17.0.

String memberAssertionComponent = (idempotencyComponent.isEmpty() ? "!" : "");

String queryValue = getInputValue(
Expand Down Expand Up @@ -1005,11 +1000,6 @@ private void writeNormalHeader(GenerationContext context, HttpBinding binding) {
target
);
boolean isIdempotencyToken = binding.getMember().hasTrait(IdempotencyTokenTrait.class);
if (isIdempotencyToken) {
context.getWriter()
.addDependency(TypeScriptDependency.UUID_TYPES)
.addImport("v4", "generateIdempotencyToken", TypeScriptDependency.UUID);
}

boolean headerAssertion = headerValue.endsWith("!");
String headerBaseValue = (headerAssertion
Expand All @@ -1022,7 +1012,7 @@ private void writeNormalHeader(GenerationContext context, HttpBinding binding) {
String s = headerBuffer.get(headerKey);
defaultValue = " || " + s.substring(s.indexOf(": ") + 2, s.length() - 1);
} else if (isIdempotencyToken) {
defaultValue = " ?? generateIdempotencyToken()";
defaultValue = " ?? crypto.randomUUID()";
}

String headerValueExpression = headerAssertion && !defaultValue.isEmpty()
Expand All @@ -1046,7 +1036,7 @@ private void writeNormalHeader(GenerationContext context, HttpBinding binding) {
String s = headerBuffer.get(headerKey);
constructedHeaderValue += " || " + s.substring(s.indexOf(": ") + 2, s.length() - 1);
} else if (isIdempotencyToken) {
constructedHeaderValue += " ?? generateIdempotencyToken()";
constructedHeaderValue += " ?? crypto.randomUUID()";
} else {
constructedHeaderValue = headerValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,7 @@ protected void serializeStructure(ProtocolGenerator.GenerationContext context, S
boolean isUnaryCall = UnaryFunctionCall.check(valueExpression);

if (memberShape.hasTrait(IdempotencyTokenTrait.class)) {
writer
.addDependency(TypeScriptDependency.UUID_TYPES)
.addImport("v4", "generateIdempotencyToken", TypeScriptDependency.UUID);

writer.write("'$L': [true, _ => _ ?? generateIdempotencyToken()],", memberName);
writer.write("'$L': [true, _ => _ ?? crypto.randomUUID()],", memberName);
} else {
if (valueProvider.equals("_ => _")) {
writer.write("'$1L': [],", memberName);
Expand Down
Loading