Skip to content

Conversation

@angelsanzn
Copy link

@angelsanzn angelsanzn commented Dec 6, 2025

createId: defer initialization until first usage, to support running cuid2 on Cloudflare Workers. Fixes #112

Having just the initialization for this function in the top level of the cuid2 ESM module causes the whole cuid2 library to fail to be imported at runtime from a Cloudflare Worker, even if using dynamic import and even if using dynamic import only inside the fetch handler. CF Workers forbids usage of crypto randomness sources at the top level of any ESM module, even if evaluation of such top level code happens at a time later than startup.

Also:

  • Do you think it would be inconvenient to make this the default for all JS engines? There's no standard way (yet) to introspect whether we're running within workerd, but we could try the classic way of checking for runtime-specific globals (WebsocketPair or caches.default should work)

…ning cuid2 on Cloudflare Workers

Having this initialization in the top level of the ESM module causes cuid2 to fail to be imported at runtime from a Cloudflare Worker, even if using dynamic import and even if using it only inside the fetch handler. CF Workers forbids (https://developers.cloudflare.com/workers/runtime-apis/handlers) usage of crypto randomness sources at the top level of any ESM module, even if evaluation of such top level code happens at a time later than startup.
@angelsanzn
Copy link
Author

@ericelliott

@ericelliott
Copy link
Collaborator

@cursor please /review

Copy link
Contributor

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 PR addresses issue #112 by deferring the initialization of createId until first usage, enabling the cuid2 library to run on Cloudflare Workers. Cloudflare Workers prohibit the use of crypto randomness sources at the top level of ESM modules, so the initialization must be lazy.

Key Changes:

  • Replaced immediate initialization of createId with a lazy initialization pattern
  • Added a lazy helper function to wrap init() and defer execution until first use

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

if (!initialized) {
initialized = fn();
}
return initialized();
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The lazy initialization has a logic error. The variable initialized stores the result of fn() (which is the cuid2() function), but then tries to call initialized() again on line 141. This creates a double function call where the returned cuid2 function is invoked without arguments, then its return value (a string ID) is invoked as a function, which will cause a runtime error.

The fix should be to return initialized directly without the extra call:

return initialized;

Copilot uses AI. Check for mistakes.
@ericelliott
Copy link
Collaborator

@cursoragent please /review - please also validate copilot's comment.

@angelsanzn
Copy link
Author

@ericelliott Apparently Cursor will not show up and Copilot's comment is wrong.

@ericelliott
Copy link
Collaborator

Thanks for the heads up. I'll investigate in depth as soon as I have a moment. In the meantime, feel free to use your own fork while I sort this out and push a new release with a fix. I appreciate you!

🙏

@angelsanzn
Copy link
Author

No worries. Do reach out if you need any more detail about what I investigated.

@ericelliott
Copy link
Collaborator

ericelliott commented Dec 19, 2025 via email

@angelsanzn
Copy link
Author

angelsanzn commented Dec 23, 2025

For that, a slightly deeper form of static analysis (done just by looking) should suffice: lazy is only called once, getting the function init as its only arg. This function "lazy" is called, not at the time the ESM module initializes but at a later time. It's called only once, its return value being stored in a closure. The return value of the init function is the createId function, as shown by the previous diff (the red part). So it can be called too.

Both cuid2 test scripts pass all the same with or without this patch, I ran them on my machine. And I have successfully tested this patched version against a live CF Workers deployment.

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.

Incompatibility issue in production build with cloudflare worker from 3.0.1

2 participants