Skip to content

fix(ai-event-client): defer devtools runtime-id generation to first use - #683

Merged
AlemTuzlak merged 1 commit into
mainfrom
667-tanstackai-event-client-generates-a-random-runtime-id-at-module-scope-crashing-on-cloudflare-workers-edge-runtimes
Jun 2, 2026
Merged

fix(ai-event-client): defer devtools runtime-id generation to first use#683
AlemTuzlak merged 1 commit into
mainfrom
667-tanstackai-event-client-generates-a-random-runtime-id-at-module-scope-crashing-on-cloudflare-workers-edge-runtimes

Conversation

@tombeckenham

@tombeckenhamtombeckenham commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🎯 Changes

@tanstack/ai-event-client seeded its devtools runtime id at module scope (a top-level IIFE calling crypto.randomUUID() / Math.random()). Because @tanstack/ai's chat() always pulls in the devtools middleware, this RNG ran at module-evaluation time — and Cloudflare Workers / edge runtimes forbid generating random values in global scope, so importing chat() crashed the Worker at startup/prerender (Disallowed operation called within global scope).

Fix: generate the runtime id lazily on first use (in getAIDevtoolsRuntimeId() / createAIDevtoolsEventEnvelope()) and memoize it, so module evaluation does no RNG. The cross-bundle global and generated id values are unchanged. Adds isolated regression tests asserting no RNG happens at import.

Fixes#667.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

The runtime id was seeded at module scope via a top-level IIFE calling
crypto.randomUUID() / Math.random(). Because @tanstack/ai's chat() always
pulls in the devtools middleware, this random-value generation ran at
module-evaluation time. Edge runtimes such as Cloudflare Workers forbid
generating random values in global scope, so importing chat() crashed the
Worker with "Disallowed operation called within global scope".
Generate the runtime id lazily on first use (inside getAIDevtoolsRuntimeId()
/ createAIDevtoolsEventEnvelope()) and memoize it, so evaluating the module
performs no random-value generation. The cross-bundle global and the
generated values are unchanged.
Fixes#667.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR defers devtools runtime-id generation from module-load time to first function call by replacing eager, top-level initialization with a memoized getRuntimeId() helper. This prevents randomness calls during module evaluation, fixing crashes in edge/global runtimes while preserving the global cache and generated values.

Changes

Lazy runtime-id initialization

Layer / File(s)Summary
Lazy runtime-id memoization and integration
packages/ai-event-client/src/envelope.ts, .changeset/lazy-runtime-id.md
Introduces memoized getRuntimeId() that lazily generates and caches globalThis.__TANSTACK_AI_DEVTOOLS_RUNTIME_ID__ on first call, then updates createAIDevtoolsEventEnvelope, eventId generation, and getAIDevtoolsRuntimeId() to call it instead of using a module-scope eager constant. Changeset documents the behavioral fix and affected packages.
Lazy initialization test suite
packages/ai-event-client/tests/runtime-id.test.ts
Validates that module import does not invoke RNG, runtime-id is generated lazily on first function call, global preseed is respected, memoization is stable, and Math.random fallback works when crypto.randomUUID is unavailable.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Poem

🐰 Lazy hops beat eager feet,
Memos cache where calls first meet,
No RNG on load, oh how sweet!
Runtime-id defers with care,
Global scopes now breathe fresh air! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title accurately summarizes the main change: deferring devtools runtime-id generation to first use, addressing the root cause of the edge runtime compatibility issue.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Description check✅ PassedThe pull request description comprehensively covers all required template sections with clear explanations of changes, motivation, checklist completion, and release impact.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 667-tanstackai-event-client-generates-a-random-runtime-id-at-module-scope-crashing-on-cloudflare-workers-edge-runtimes

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.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

1 package(s) bumped directly, 18 bumped as dependents.

🟩 Patch bumps

PackageVersionReason
@tanstack/ai-event-client0.5.1 → 0.5.2Changeset
@tanstack/ai0.26.0 → 0.26.1Dependent
@tanstack/ai-client0.15.2 → 0.15.3Dependent
@tanstack/ai-code-mode0.2.2 → 0.2.3Dependent
@tanstack/ai-code-mode-skills0.2.2 → 0.2.3Dependent
@tanstack/ai-devtools-core0.4.5 → 0.4.6Dependent
@tanstack/ai-fal0.7.20 → 0.7.21Dependent
@tanstack/ai-isolate-cloudflare0.2.18 → 0.2.19Dependent
@tanstack/ai-isolate-node0.1.27 → 0.1.28Dependent
@tanstack/ai-isolate-quickjs0.1.27 → 0.1.28Dependent
@tanstack/ai-preact0.8.2 → 0.8.3Dependent
@tanstack/ai-react0.14.2 → 0.14.3Dependent
@tanstack/ai-solid0.12.2 → 0.12.3Dependent
@tanstack/ai-svelte0.12.2 → 0.12.3Dependent
@tanstack/ai-vue0.12.2 → 0.12.3Dependent
@tanstack/ai-vue-ui0.2.11 → 0.2.12Dependent
@tanstack/preact-ai-devtools0.1.48 → 0.1.49Dependent
@tanstack/react-ai-devtools0.2.48 → 0.2.49Dependent
@tanstack/solid-ai-devtools0.2.48 → 0.2.49Dependent

@nx-cloud

nx-cloudBot commented Jun 2, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 144a376

CommandStatusDurationResult
nx run-many --targets=build --exclude=examples/...✅ Succeeded1m 7sView ↗

☁️ Nx Cloud last updated this comment at 2026-06-02 05:57:43 UTC

@pkg-pr-new

pkg-pr-newBot commented Jun 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@683

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@683

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@683

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@683

@tanstack/ai-code-mode-skills

npm i https://pkg.pr.new/@tanstack/ai-code-mode-skills@683

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@683

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@683

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@683

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@683

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@683

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@683

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@683

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@683

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@683

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@683

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@683

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@683

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@683

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@683

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@683

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@683

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@683

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@683

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@683

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@683

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@683

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@683

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@683

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@683

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@683

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@683

commit: 144a376

@tombeckenham
tombeckenham marked this pull request as draft June 2, 2026 05:59

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/ai-event-client/tests/runtime-id.test.ts (1)

87-112: 💤 Low value

Consider improving crypto restoration logic.

The current cleanup restores crypto only when cryptoDescriptor is truthy. If crypto didn't exist originally on globalThis (unlikely in modern environments, but possible), cryptoDescriptor would be undefined, and the finally block would leave crypto set to undefined instead of deleting the property. This could affect subsequent tests.

♻️ Suggested improvement
 } finally {
if (cryptoDescriptor) {
Object.defineProperty(globalThis, 'crypto', cryptoDescriptor)
+ } else {+ Reflect.deleteProperty(globalThis, 'crypto')
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-event-client/tests/runtime-id.test.ts` around lines 87 - 112,
Update the test cleanup to restore globalThis.crypto correctly: after
temporarily setting globalThis.crypto = undefined (using Object.defineProperty)
ensure the finally block either restores the original descriptor when
cryptoDescriptor is defined or deletes the temporary crypto property when
cryptoDescriptor is undefined; reference the cryptoDescriptor variable and the
call to getAIDevtoolsRuntimeId in this test so Math.random spy behavior remains
isolated and subsequent tests don’t see a lingering undefined crypto.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/ai-event-client/tests/runtime-id.test.ts`:
- Around line 87-112: Update the test cleanup to restore globalThis.crypto
correctly: after temporarily setting globalThis.crypto = undefined (using
Object.defineProperty) ensure the finally block either restores the original
descriptor when cryptoDescriptor is defined or deletes the temporary crypto
property when cryptoDescriptor is undefined; reference the cryptoDescriptor
variable and the call to getAIDevtoolsRuntimeId in this test so Math.random spy
behavior remains isolated and subsequent tests don’t see a lingering undefined
crypto.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f0151164-0eb4-4e59-a104-021b4fb48a24

📥 Commits

Reviewing files that changed from the base of the PR and between 86cf41c and 144a376.

📒 Files selected for processing (3)
  • .changeset/lazy-runtime-id.md
  • packages/ai-event-client/src/envelope.ts
  • packages/ai-event-client/tests/runtime-id.test.ts

@tombeckenham
tombeckenham marked this pull request as ready for review June 2, 2026 06:01
@AlemTuzlak
AlemTuzlak merged commit 7adff0f into mainJun 2, 2026
10 checks passed
@AlemTuzlak
AlemTuzlak deleted the 667-tanstackai-event-client-generates-a-random-runtime-id-at-module-scope-crashing-on-cloudflare-workers-edge-runtimes branch June 2, 2026 06:32
@github-actionsgithub-actionsBot mentioned this pull request Jun 2, 2026
Sign up for freeto 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.

@tanstack/ai-event-client generates a random runtime ID at module scope, crashing on Cloudflare Workers / edge runtimes

2 participants

@tombeckenham@AlemTuzlak