Skip to content

Conversation

@dplewis
Copy link
Member

@dplewis dplewis commented Jan 8, 2026

Pull Request

Issue

Using node:crypto prevented users from polyfilling randomUUID

Closes: #2856

Approach

As of Node 18 Web Crypto API is now a global object, this global object is also included in the browser. For any other runtime it will need to be polyfilled if not supported.

Summary by CodeRabbit

  • Bug Fixes

    • Improved error messaging for UUID generation when cryptographic services are unavailable, including guidance for alternative implementations.
  • Tests

    • Added test case for UUID generation error handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@parse-github-assistant
Copy link

parse-github-assistant bot commented Jan 8, 2026

🚀 Thanks for opening this pull request!

@coderabbitai
Copy link

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

The PR simplifies UUID generation by consolidating environment-specific branching logic into a single implementation using crypto.randomUUID() with a runtime guard. It removes conditional logic for weapp, browser, and Node environments, replacing it with a direct call and error handling that throws a descriptive message if crypto.randomUUID is unavailable.

Changes

Cohort / File(s) Summary
Implementation
src/uuid.ts
Replaced multi-branch UUID generation with unified crypto.randomUUID() implementation. Changed declaration from let to const function. Added runtime guard that throws error if crypto API unavailable. Removed environment-specific branching (weapp/browser/Node).
Type Declarations
types/uuid.d.ts
Updated type declaration from declare let uuid to declare const uuid to match implementation. API surface and export remain unchanged.
Tests
src/__tests__/browser-test.js
Added test case validating error behavior when crypto.randomUUID is unavailable. Test temporarily deletes global.crypto, verifies thrown error message guides users to react-native-random-uuid for React Native environments.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: addressing React Native build failures caused by crypto.randomUUID dependency.
Linked Issues check ✅ Passed The PR successfully addresses the core requirement from #2856: using a global crypto.randomUUID that allows polyfilling instead of directly importing Node's crypto module, enabling React Native/Expo compatibility.
Out of Scope Changes check ✅ Passed All changes are focused on the uuid implementation and related tests; no out-of-scope modifications detected beyond the linked issue requirements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description includes required sections and provides context for the issue and approach, though the Tasks section is partially incomplete.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@parseplatformorg
Copy link
Contributor

parseplatformorg commented Jan 8, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@codecov
Copy link

codecov bot commented Jan 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (8cb510c) to head (6e4fb95).

Additional details and impacted files
@@            Coverage Diff            @@
##             alpha     #2858   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           64        64           
  Lines         6222      6212   -10     
  Branches      1473      1487   +14     
=========================================
- Hits          6222      6212   -10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @README.md:
- Line 10: The Node.js version badge excludes v18 while the compatibility table
(lines ~54–57) still lists v18; update the badge string in README.md to include
18 (e.g., change "20,_22,_24" to "18,_20,_22,_24") and verify the compatibility
table and any other references now match the badge; alternatively, if you intend
to drop v18 support, remove it from the compatibility table instead—ensure both
the badge and table are consistent.
- Around line 97-99: Replace the ES6 import of the polyfill with the same
CommonJS style used elsewhere: change the line that imports
'react-native-random-uuid' so it uses require() rather than import, ensuring the
polyfill still provides crypto.randomUUID() globally; keep the surrounding
comment about Parse version comparison as-is until the exact version is
confirmed.

In @src/uuid.ts:
- Line 1: The uuid helper currently calls crypto.randomUUID() directly which
throws a cryptic ReferenceError when crypto or crypto.randomUUID is missing;
update the uuid function to perform a runtime check (typeof crypto !==
'undefined' && typeof crypto.randomUUID === 'function') and throw a clear,
actionable Error if unavailable that explains how to polyfill in React Native
(mention importing "react-native-random-uuid" after Parse.setAsyncStorage() and
link to the README), otherwise return crypto.randomUUID(); reference the
existing uuid function in src/uuid.ts to locate and replace the direct call.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf2ef13 and a79469c.

📒 Files selected for processing (2)
  • README.md
  • src/uuid.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build (Node 20, 20.19.0)
  • GitHub Check: build (Node 24, 24.1.0)
  • GitHub Check: build (Node 22, 22.12.0)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @types/uuid.d.ts:
- Line 1: The current uuid implementation relies on crypto.randomUUID() which
will crash in React Native; update the module used by the declared function uuid
to provide a RN-safe implementation by either adding a React Native specific
file (e.g., create uuid.react-native.ts or lib/react-native/uuid.js) that
returns the same `${string}-${string}-...` format using a RN-friendly polyfill
(like react-native-uuid or the uuid package), or modify src/uuid.ts to detect
React Native at runtime and fall back to the polyfill when crypto.randomUUID is
unavailable; ensure InstallationController.currentInstallationId() and other
callers import the unified uuid symbol so RN builds pick up the RN variant or
the runtime fallback.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a79469c and 1b8aa51.

📒 Files selected for processing (3)
  • types/AnonymousUtils.d.ts
  • types/Parse.d.ts
  • types/uuid.d.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build (Node 24, 24.1.0)
  • GitHub Check: build (Node 20, 20.19.0)
  • GitHub Check: build (Node 22, 22.12.0)
🔇 Additional comments (2)
types/AnonymousUtils.d.ts (1)

79-79: LGTM! Type narrowing accurately represents UUID format.

The template literal type ${string}-${string}-${string}-${string}-${string} correctly represents the standard UUID format. Since this is within the _getAuthProvider() method (indicated by the _ prefix as a private API), the type narrowing has minimal breaking change risk.

types/Parse.d.ts (1)

36-36: LGTM! Consistent type narrowing across Parse namespace.

The type change for authData.id is consistent with the same change in types/AnonymousUtils.d.ts, maintaining type consistency across the Parse namespace declarations.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @README.md:
- Line 10: The README badge was updated to list Node 20, 22, 24 but the
compatibility table still lists Node 18; update the README to be consistent by
either removing Node 18 from the compatibility table to match the badge, or keep
Node 18 and add an explicit note that Node 18 requires a polyfill for global
crypto.randomUUID (requirement: Node >=19 provides it natively); reference the
badge token "[![Node Version]...]" and the compatibility table section and
ensure the README clearly states the native requirement (Node ≥19) or documents
how to provide the polyfill for Node 18 users.
🧹 Nitpick comments (3)
README.md (1)

89-97: Consider documenting the crypto polyfill requirement for React Native.

React Native users will now need to polyfill crypto.randomUUID since this PR removes the Node crypto import. Consider adding a note here to guide users, for example:

**Note:** React Native environments require a crypto polyfill. Install and import `react-native-random-uuid` or similar before initializing Parse.
src/__tests__/browser-test.js (1)

165-176: Improve cleanup reliability with try-finally.

The test correctly validates the error path, but if uuidv4() unexpectedly succeeds (line 171 fails), global.crypto won't be restored. Use a finally block to guarantee cleanup:

♻️ Suggested refactor
   it('throw error if randomUUID is not available', () => {
     const tmp = global.crypto;
     delete global.crypto;
     try {
       const uuidv4 = require('../uuid').default;
       uuidv4();
       expect(true).toBe(false);
     } catch (e) {
       expect(e.message).toBe('crypto.randomUUID is not available. For React Native, import "react-native-random-uuid"');
+    } finally {
+      global.crypto = tmp;
     }
-    global.crypto = tmp;
   });
src/uuid.ts (1)

3-6: Consider a more generic error message for broader environment coverage.

The error message specifically guides React Native users but this check applies to any environment without crypto.randomUUID (e.g., older Node.js versions, older browsers). Consider a more inclusive message:

💬 Suggested alternative
     throw new Error(
-      'crypto.randomUUID is not available. ' +
-      'For React Native, import "react-native-random-uuid"'
+      'crypto.randomUUID is not available. ' +
+      'Please provide a polyfill (e.g., "react-native-random-uuid" for React Native)'
     );
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b8aa51 and 7ba5b9b.

📒 Files selected for processing (3)
  • README.md
  • src/__tests__/browser-test.js
  • src/uuid.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/__tests__/browser-test.js (1)
integration/test/ParseUserTest.js (2)
  • uuidv4 (5-5)
  • require (6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build (Node 24, 24.1.0)
  • GitHub Check: build (Node 20, 20.19.0)
  • GitHub Check: build (Node 22, 22.12.0)
🔇 Additional comments (1)
src/uuid.ts (1)

1-9: No changes needed. The implementation correctly assumes crypto.randomUUID is available globally in Node.js 20+ (introduced without experimental flag in v19.0.0). The error handling appropriately guards against environments where it's unavailable, such as React Native, making this a robust solution for both Node.js and React Native use cases.

@dplewis dplewis requested a review from a team January 8, 2026 17:47
@mtrezza mtrezza requested review from Copilot and removed request for a team January 12, 2026 11:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request addresses React Native build failures caused by the use of node:crypto module by migrating to the global crypto object available in modern JavaScript environments. The change allows users to polyfill crypto.randomUUID in environments where it's not natively available.

Changes:

  • Simplified UUID implementation to use global crypto.randomUUID() with runtime availability check
  • Removed environment-specific UUID generation logic (weapp, browser, Node.js)
  • Added error handling with guidance for React Native users when crypto.randomUUID is unavailable
  • Changed type definition from let to const for consistency

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

File Description
types/uuid.d.ts Updated type declaration from let to const to match the new implementation
src/uuid.ts Replaced environment-specific UUID implementations with a single implementation using global crypto object, throws error if unavailable
src/tests/browser-test.js Added test case to verify error handling when crypto.randomUUID is not available

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2 to +8
if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function') {
throw new Error(
'crypto.randomUUID is not available. ' +
'For React Native, import "react-native-random-uuid"'
);
}
return crypto.randomUUID();
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

The new uuid implementation relies on the global crypto object being available. However, the WeChat mini-program (weapp) environment may not have the crypto object or crypto.randomUUID available. The previous implementation had a custom fallback UUID generation for weapp. This change could break the existing weapp test that expects uuid to work in that environment (see src/tests/weapp-test.js line 58-62). Consider adding a fallback implementation for environments where crypto.randomUUID is not available, or verify that weapp does indeed support crypto.randomUUID.

Suggested change
if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function') {
throw new Error(
'crypto.randomUUID is not available. ' +
'For React Native, import "react-native-random-uuid"'
);
}
return crypto.randomUUID();
// Prefer native crypto.randomUUID when available
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
// Fallback implementation for environments without crypto.randomUUID
// (e.g., WeChat mini-program, older browsers, some React Native setups)
let d = Date.now();
let d2 =
typeof performance !== 'undefined' && typeof performance.now === 'function'
? performance.now() * 1000
: 0;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
let r = Math.random() * 16;
if (d > 0) {
r = (d + r) % 16 | 0;
d = Math.floor(d / 16);
} else {
r = (d2 + r) % 16 | 0;
d2 = Math.floor(d2 / 16);
}
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +5
'crypto.randomUUID is not available. ' +
'For React Native, import "react-native-random-uuid"'
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

The error message specifically mentions React Native and suggests importing "react-native-random-uuid", but this error will be thrown in any environment where crypto.randomUUID is not available, including WeChat mini-programs (weapp). The error message should be more generic to cover all unsupported environments, or provide environment-specific guidance.

Suggested change
'crypto.randomUUID is not available. ' +
'For React Native, import "react-native-random-uuid"'
'crypto.randomUUID is not available in this environment. ' +
'Use a UUID polyfill or environment-specific implementation (for example, in React Native you can import "react-native-random-uuid").'

Copilot uses AI. Check for mistakes.
Comment on lines +174 to +175
}
global.crypto = tmp;
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

This test doesn't have proper cleanup if the test fails before global.crypto is restored. If the uuidv4() call doesn't throw an error as expected, global.crypto will remain deleted, potentially affecting other tests. Consider using a finally block or Jest's afterEach/beforeEach hooks to ensure proper cleanup.

Suggested change
}
global.crypto = tmp;
} finally {
global.crypto = tmp;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The package at "node_modules\parse\lib\react-native\uuid.js" attempted to import the Node standard library module "crypto".

3 participants