Skip to content

feat: add React Native AI support#647

Open
AlemTuzlak wants to merge 3 commits into
mainfrom
investigate/react-native-support
Open

feat: add React Native AI support#647
AlemTuzlak wants to merge 3 commits into
mainfrom
investigate/react-native-support

Conversation

@AlemTuzlak
Copy link
Copy Markdown
Contributor

@AlemTuzlak AlemTuzlak commented May 26, 2026

Summary

  • Add React Native support docs, package export compatibility, smoke fixture, and example app.
  • Add React Native smoke validation for import surface, Expo bundling, and esbuild bundling.
  • Fix post-rebase devtools build blocker by using a TypeScript 5-compatible ignoreDeprecations value in @tanstack/ai-devtools-core.

Local validation

  • pnpm install --frozen-lockfile (prior worker)
  • pnpm --filter ts-react-native-chat smoke (prior worker)
  • pnpm run test:react-native (prior worker)
  • pnpm test:docs (prior worker)
  • pnpm nx run @tanstack/ai-devtools-core:test:types
  • pnpm nx run @tanstack/ai-devtools-core:build
  • pnpm run test:pr
  • pnpm run build:all
  • pnpm --filter @tanstack/ai-e2e test:e2e (exit 0; 208 passed, 8 flaky retries reported)
  • git diff --check

Summary by CodeRabbit

  • New Features

    • React Native / Expo support: headless chat hooks, mobile-compatible connection adapters, and a fetcher option for chat clients/hooks.
    • New XHR-based streaming transports (XHR SSE and XHR HTTP) and improved client-safe streaming utilities.
  • Documentation

    • React Native Quick Start, transport selection guidance, Expo example walkthrough, and troubleshooting added.
  • Tests

    • React Native smoke tests, example app, and bundle/import-surface verification scripts added.
  • Bug Fixes

    • Clearer streaming diagnostics with actionable unsupported-stream errors.

Review Change Stack

@AlemTuzlak AlemTuzlak requested a review from a team as a code owner May 26, 2026 20:39
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a9b3583-955f-45ba-b196-dcf2427185e1

📥 Commits

Reviewing files that changed from the base of the PR and between e26ba48 and d8d0d09.

📒 Files selected for processing (3)
  • testing/e2e/tests/tools-test/approval-flow.spec.ts
  • testing/e2e/tests/tools-test/helpers.ts
  • testing/e2e/tests/tools-test/race-conditions.spec.ts

📝 Walkthrough

Walkthrough

Adds React Native/Expo support: XHR-based streaming adapters and shared fetch-response utilities, a public @tanstack/ai/client entrypoint (EventType + barrel exports), examples (Expo + Hono), smoke tests, docs, and import refactoring to use the client subpath across packages and tests.

Changes

Mobile streaming adapters and client entrypoint

Layer / File(s) Summary
Response stream utilities for mobile runtime detection
packages/ai-client/src/response-stream.ts, packages/ai-client/src/sse-utils.ts
Adds MissingResponseStreamFeature and UnsupportedResponseStreamError, getResponseStreamReader, createResponseStreamTextDecoder, and parseSseDataLine() to validate streaming-capable runtimes and normalize SSE data: lines.
XHR-based chat adapters for mobile transports
packages/ai-client/src/connection-adapters.ts, packages/ai-client/tests/connection-adapters-xhr.test.ts
New xhrServerSentEvents and xhrHttpStream adapters using XMLHttpRequest for SSE and NDJSON streaming, plus shared buildRunAgentInputBody and integration with response-stream utilities; includes comprehensive XHR tests.
Public @tanstack/ai/client entrypoint and EventType
packages/ai/src/client.ts, packages/ai/vite.config.ts, packages/ai/package.json
Introduces EventType enum and barrel exports consolidating tool helpers, schema conversion, message/stream utilities, types, and realtime types; Vite and package exports updated to expose the client subpath.
Import refactor: @tanstack/ai@tanstack/ai/client
packages/ai-client/src/*.ts, tests, and framework packages
Refactors type/value imports across ai-client implementation and tests to source from @tanstack/ai/client; framework barrels updated to re-export XHR adapters and XhrConnectionOptions.
Updated fetch and XHR adapter tests
packages/ai-client/tests/*
Adapter tests now assert structured UnsupportedResponseStreamError with missingFeature metadata, handle data: frames without spaces, and include TextDecoder absence checks; new XHR suite validates parsing, status/error/abort behaviors.

React Native/Expo example apps and smoke testing

Layer / File(s) Summary
React Native chat example: Expo and Metro configuration
examples/ts-react-native-chat/app.json, examples/ts-react-native-chat/index.ts, examples/ts-react-native-chat/metro.config.cjs, examples/ts-react-native-chat/package.json, examples/ts-react-native-chat/tsconfig.json
Adds a full Expo example with Metro config that enforces singleton resolution and .js.ts/.tsx rewrites, package scripts, and TS config for the example.
React Native chat example: Hono server with streaming endpoints
examples/ts-react-native-chat/src/server/app.ts, examples/ts-react-native-chat/src/server/index.ts
Hono backend exposing /health, /chat/http (NDJSON) and /chat/sse (SSE), streaming structured recipe outputs via TanStack AI/OpenAI with server-side tools and error streaming.
React Native chat example: UI with recipe display and transport selection
examples/ts-react-native-chat/src/App.tsx
Native chat UI using useChat with selectable transports (fetch-http, xhr-http, xhr-sse), parsing structured-output parts into a recipe UI and handling fetch-stream unsupported errors.
React Native chat example: Dev runner and LAN IP detection
examples/ts-react-native-chat/scripts/dev.mjs, examples/ts-react-native-chat/scripts/dev.test.mjs
Dev script that detects LAN IP, separates server-only env from Expo-public env, spawns backend + Expo, and tests covering IP selection, env isolation, and platform spawn behavior.
React Native chat example: Server smoke tests and React singleton verification
examples/ts-react-native-chat/scripts/smoke-server.ts, examples/ts-react-native-chat/scripts/verify-react-resolution.mjs
Smoke tests validate endpoints with/without API key, stream chunk expectations, and verify consistent React/react-native singleton resolution across example origins.
React Native chat example: Setup and usage documentation
examples/ts-react-native-chat/README.md, examples/ts-react-native-chat/.gitignore
Adds README with setup, env, run, troubleshooting, and validation commands; .gitignore excludes Expo output.
React Native smoke fixture: Minimal app and validation tests
testing/react-native-smoke/, testing/react-native-smoke/src/App.tsx, testing/react-native-smoke/scripts/assert-import-surface.ts, testing/react-native-smoke/scripts/assert-bundle-output.ts, testing/react-native-smoke/scripts/esbuild-smoke.ts
Lightweight smoke fixture that typechecks, enforces import-surface constraints, builds an esbuild browser bundle (with a RN runtime stub), and validates bundle contents for forbidden tokens.

React Native documentation and quick start guides

Layer / File(s) Summary
React Native quick start guide with server and troubleshooting
docs/getting-started/quick-start-react-native.md
New quick start covering Hono backend with NDJSON/SSE, Expo base URL setup, useChat example using xhrHttpStream, transport selection guidance, and troubleshooting.
API docs: Connection adapters and React Native support
docs/api/ai-client.md, docs/api/ai-react.md
Expanded adapter docs covering fetchHttpStream, xhrHttpStream, xhrServerSentEvents, runtime requirements, option fields, body/forwardedProps merging, and stream errors (UnsupportedResponseStreamError, StreamTruncatedError). React Native notes added.
Connection adapters guide: Transport selection and React Native
docs/chat/connection-adapters.md
Updated guidance recommending XHR adapters for React Native/Expo by default, with fetchHttpStream only when fetch streaming is supported; documents pairing with server response helpers.
Getting started updates and navigation
docs/getting-started/overview.md, docs/getting-started/quick-start.md, docs/config.json
Adds React Native / Expo bullets, Quick Start navigation entry, and callouts in the web quick start to point mobile users to the RN guide.
Tree-shaking and structured outputs documentation
docs/advanced/tree-shaking.md, docs/structured-outputs/multi-turn.md
Tree-shaking best-practices updated to advise mobile chat bundles remain client-only; links to RN example for multi-turn structured outputs.

Workspace and package configuration

Layer / File(s) Summary
Root package.json: Test orchestration and dependency handling
package.json
Prepends pnpm run test:react-native to test:pr/test:ci and extends test:sherif to ignore specified dependency versions for workspace compatibility.
DevTools packages: NODE_ENV declarations
packages/ai-devtools/src/env.d.ts, packages/preact-ai-devtools/src/env.d.ts, packages/react-ai-devtools/src/env.d.ts, packages/solid-ai-devtools/src/env.d.ts, packages/ai-devtools/tsconfig.json
Adds ambient process.env.NODE_ENV declarations and relaxes ai-devtools compiler deprecation warnings.
pnpm workspace configuration
pnpm-workspace.yaml
Adds trustPolicyExclude entries and disables msgpackr-extract build permission.
Release announcement
.changeset/react-native-ai-support.md
Changeset describing minor releases across @tanstack/ai* packages announcing RN support, fetcher changes, client subpath, XHR adapters, docs, examples, and smoke tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • TanStack/ai#511: Related work on RunAgentInput/wire-format and adapter request-body construction that aligns with the new shared body builder.
  • TanStack/ai#512: Related to adding the fetcher option and Response vs AsyncIterable handling in ChatClient/hooks.

Suggested reviewers

  • crutchcorn

"🐰 Hopped through docs and streams so bright,
XHR hums softly into mobile night,
Expo finds the LAN and routes just right,
Recipes stream in cards of pure delight,
A tiny rabbit cheers the code's new light."

✨ 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 investigate/react-native-support

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

🚀 Changeset Version Preview

7 package(s) bumped directly, 23 bumped as dependents.

🟥 Major bumps

Package Version Reason
@tanstack/ai-preact 0.6.34 → 1.0.0 Changeset
@tanstack/ai-react 0.12.0 → 1.0.0 Changeset
@tanstack/ai-solid 0.10.9 → 1.0.0 Changeset
@tanstack/ai-svelte 0.10.9 → 1.0.0 Changeset
@tanstack/ai-vue 0.10.10 → 1.0.0 Changeset
@tanstack/ai-anthropic 0.11.0 → 1.0.0 Dependent
@tanstack/ai-code-mode 0.1.21 → 1.0.0 Dependent
@tanstack/ai-code-mode-skills 0.1.21 → 1.0.0 Dependent
@tanstack/ai-elevenlabs 0.2.12 → 1.0.0 Dependent
@tanstack/ai-event-client 0.3.11 → 1.0.0 Dependent
@tanstack/ai-fal 0.7.14 → 1.0.0 Dependent
@tanstack/ai-gemini 0.12.0 → 1.0.0 Dependent
@tanstack/ai-grok 0.9.0 → 1.0.0 Dependent
@tanstack/ai-groq 0.2.7 → 1.0.0 Dependent
@tanstack/ai-isolate-node 0.1.21 → 1.0.0 Dependent
@tanstack/ai-isolate-quickjs 0.1.21 → 1.0.0 Dependent
@tanstack/ai-ollama 0.6.22 → 1.0.0 Dependent
@tanstack/ai-openai 0.10.2 → 1.0.0 Dependent
@tanstack/ai-openrouter 0.9.8 → 1.0.0 Dependent
@tanstack/ai-react-ui 0.8.2 → 1.0.0 Dependent
@tanstack/ai-solid-ui 0.7.2 → 1.0.0 Dependent
@tanstack/openai-base 0.4.0 → 1.0.0 Dependent

🟨 Minor bumps

Package Version Reason
@tanstack/ai 0.22.0 → 0.23.0 Changeset
@tanstack/ai-client 0.12.0 → 0.13.0 Changeset

🟩 Patch bumps

Package Version Reason
@tanstack/ai-devtools-core 0.3.38 → 0.3.39 Dependent
@tanstack/ai-isolate-cloudflare 0.2.12 → 0.2.13 Dependent
@tanstack/ai-vue-ui 0.2.5 → 0.2.6 Dependent
@tanstack/preact-ai-devtools 0.1.42 → 0.1.43 Dependent
@tanstack/react-ai-devtools 0.2.42 → 0.2.43 Dependent
@tanstack/solid-ai-devtools 0.2.42 → 0.2.43 Dependent

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 26, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedexpo@​56.0.577100100100100
Addedexpo@​54.0.347710078100100
Added@​types/​react@​19.1.171001007996100
Addedreact@​19.1.01001008496100
Addedreact-native@​0.85.39110099100100
Addedreact-native@​0.81.59110099100100
Added@​hono/​node-server@​1.19.1410010010096100
Addedhono@​4.12.23991009796100

View full report

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 26, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Publisher changed: npm @expo/expo-modules-macros-plugin is now published by tsapeta

Author: tsapeta

From: pnpm-lock.yamlnpm/expo@56.0.5npm/@expo/expo-modules-macros-plugin@0.0.9

ℹ Read more on: This package | This alert | What is unstable ownership?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Try to reduce the number of authors you depend on to reduce the risk to malicious actors gaining access to your supply chain. Packages should remove inactive collaborators with publishing rights from packages on npm.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@expo/expo-modules-macros-plugin@0.0.9. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Publisher changed: npm @expo/spawn-async is now published by philpl

Author: philpl

From: pnpm-lock.yamlnpm/expo@54.0.34npm/expo@56.0.5npm/@expo/spawn-async@1.8.0

ℹ Read more on: This package | This alert | What is unstable ownership?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Try to reduce the number of authors you depend on to reduce the risk to malicious actors gaining access to your supply chain. Packages should remove inactive collaborators with publishing rights from packages on npm.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@expo/spawn-async@1.8.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm @react-native/debugger-frontend is 96.0% likely obfuscated

Confidence: 0.96

Location: Package overview

From: pnpm-lock.yamlnpm/expo@54.0.34npm/react-native@0.81.5npm/@react-native/debugger-frontend@0.81.5

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@react-native/debugger-frontend@0.81.5. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm @react-native/debugger-frontend is 96.0% likely obfuscated

Confidence: 0.96

Location: Package overview

From: pnpm-lock.yamlnpm/react-native@0.85.3npm/expo@56.0.5npm/@react-native/debugger-frontend@0.85.3

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@react-native/debugger-frontend@0.85.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Low adoption: npm fetch-nodeshim

Location: Package overview

From: pnpm-lock.yamlnpm/expo@56.0.5npm/fetch-nodeshim@0.4.10

ℹ Read more on: This package | This alert | What are unpopular packages?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Unpopular packages may have less maintenance and contain other problems.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/fetch-nodeshim@0.4.10. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Deprecated by its maintainer: npm inflight

Reason: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.

From: pnpm-lock.yamlnpm/expo@54.0.34npm/react-native@0.81.5npm/inflight@1.0.6

ℹ Read more on: This package | This alert | What is a deprecated package?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Research the state of the package and determine if there are non-deprecated versions that can be used, or if it should be replaced with a new, supported solution.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/inflight@1.0.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Deprecated by its maintainer: npm rimraf

Reason: Rimraf versions prior to v4 are no longer supported

From: pnpm-lock.yamlnpm/expo@54.0.34npm/react-native@0.81.5npm/rimraf@3.0.2

ℹ Read more on: This package | This alert | What is a deprecated package?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Research the state of the package and determine if there are non-deprecated versions that can be used, or if it should be replaced with a new, supported solution.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/rimraf@3.0.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Deprecated by its maintainer: npm uuid

Reason: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).

From: pnpm-lock.yamlnpm/expo@54.0.34npm/expo@56.0.5npm/uuid@7.0.3

ℹ Read more on: This package | This alert | What is a deprecated package?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Research the state of the package and determine if there are non-deprecated versions that can be used, or if it should be replaced with a new, supported solution.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/uuid@7.0.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 26, 2026

View your CI Pipeline Execution ↗ for commit d8d0d09

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-26 21:23:40 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 26, 2026

Open in StackBlitz

@tanstack/ai

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

@tanstack/ai-anthropic

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

@tanstack/ai-client

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

@tanstack/ai-code-mode

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

@tanstack/ai-code-mode-skills

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

@tanstack/ai-devtools-core

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

@tanstack/ai-elevenlabs

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

@tanstack/ai-event-client

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

@tanstack/ai-fal

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

@tanstack/ai-gemini

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

@tanstack/ai-grok

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

@tanstack/ai-groq

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

@tanstack/ai-isolate-cloudflare

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

@tanstack/ai-isolate-node

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

@tanstack/ai-isolate-quickjs

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

@tanstack/ai-ollama

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

@tanstack/ai-openai

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

@tanstack/ai-openrouter

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

@tanstack/ai-preact

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

@tanstack/ai-react

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

@tanstack/ai-react-ui

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

@tanstack/ai-solid

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

@tanstack/ai-solid-ui

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

@tanstack/ai-svelte

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

@tanstack/ai-utils

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

@tanstack/ai-vue

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

@tanstack/ai-vue-ui

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

@tanstack/openai-base

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

@tanstack/preact-ai-devtools

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

@tanstack/react-ai-devtools

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

@tanstack/solid-ai-devtools

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

commit: d8d0d09

Copy link
Copy Markdown
Contributor

@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: 7

🧹 Nitpick comments (1)
testing/react-native-smoke/scripts/esbuild-smoke.ts (1)

14-20: ⚡ Quick win

Consider removing the @tanstack/ai root alias.

Line 15 aliases @tanstack/ai to the root package entry, but the import surface script (assert-import-surface.ts lines 245-248) explicitly forbids importing from @tanstack/ai root, requiring @tanstack/ai/client instead.

Since the import surface validation would fail if any code imports @tanstack/ai, this alias should never be used. Including it may cause confusion or suggest the import is permitted.

Proposed removal
   alias: {
-    '`@tanstack/ai`': resolve(repoRoot, 'packages/ai/src/index.ts'),
     '`@tanstack/ai/client`': resolve(repoRoot, 'packages/ai/src/client.ts'),
🤖 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 `@testing/react-native-smoke/scripts/esbuild-smoke.ts` around lines 14 - 20,
Remove the forbidden root alias entry from the esbuild alias map: delete the
'`@tanstack/ai`': resolve(repoRoot, 'packages/ai/src/index.ts') line in the alias
object in esbuild-smoke.ts so imports must use the allowed scoped entry
('`@tanstack/ai/client`'); this aligns with the import-surface rule that disallows
importing from the '`@tanstack/ai`' root.
🤖 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.

Inline comments:
In `@docs/getting-started/quick-start.md`:
- Around line 21-25: The two adjacent blockquotes ("React Native or Expo app?
Use the headless React hooks..." and the "**Tip:** If you'd prefer not to sign
up...") are separated by a blank line which triggers markdownlint MD028; remove
the empty line between them or merge them into one contiguous blockquote so they
form a single continuous blockquote (locate the callout text starting with
"React Native or Expo app?" and the following "**Tip:**" paragraph and either
delete the blank line or combine the content into one blockquote).

In `@examples/ts-react-native-chat/package.json`:
- Around line 1-44: Add the missing packageManager field to the top-level
package.json object in examples/ts-react-native-chat by adding packageManager:
"pnpm@10.17.0" (same JSON object that contains "name", "private", "type", etc.);
ensure the property is a sibling to those keys so the package manifest follows
the **/package.json guideline.

In `@examples/ts-react-native-chat/scripts/dev.mjs`:
- Around line 338-344: The exit handler for child.on('exit') incorrectly treats
any signal-based exit as success; update the callback (the child.on('exit',
(code, signal) => { ... }) block) so that if signal is non-null you call
shutdown with a non-zero code (e.g., shutdown(1) or shutdown with a code derived
from the signal) instead of shutdown(0), and include the signal in the shutdown
invocation or log for context; keep the existing shuttingDown guard and the
existing success path for code === 0 unchanged.

In `@examples/ts-react-native-chat/scripts/smoke-server.ts`:
- Line 169: The content-type assertion in smoke-server.ts compares the entire
header string exactly, which fails when parameters like "; charset=utf-8" are
present; update the assertion that calls response.headers.get('content-type')
(the expression used in the failing assert.equal) to instead check only the
media type portion or to test startsWith/includes (e.g., trim and split on ';'
or use startsWith) and use an appropriate assertion (assert.ok/assert.match) so
the test accepts "application/x-ndjson" with optional parameters.
- Line 145: The assertion constructs a RegExp from LIVE_RECIPE_SERVER_ERROR
which can misinterpret regex metacharacters; change the check to a plain
substring match instead. Replace the call to assert.match(error.message, new
RegExp(LIVE_RECIPE_SERVER_ERROR)) with a string-based assertion such as
assert.include(error.message, LIVE_RECIPE_SERVER_ERROR) or
assert.ok(error.message.includes(LIVE_RECIPE_SERVER_ERROR)) so the test matches
the literal message text; keep references to LIVE_RECIPE_SERVER_ERROR and
error.message in the updated assertion.

In `@examples/ts-react-native-chat/src/server/index.ts`:
- Around line 11-17: The PORT env value is parsed into port using
Number.parseInt and may be NaN, which can break the call to serve; update the
initialization and before calling serve to validate the parsed port (e.g., parse
with Number.parseInt or Number(), then check Number.isFinite/Number.isInteger
and that port > 0 and within valid TCP port range), and if invalid fall back to
the default 8787 (or exit with a clear error); make this change around the
existing port variable and the serve({ fetch: app.fetch, hostname: '0.0.0.0',
port }) invocation so serve always receives a valid numeric port.

In `@pnpm-workspace.yaml`:
- Around line 6-7: Add an inline comment above the trustPolicyExclude entry in
pnpm-workspace.yaml explaining why semver@5.7.2 || 6.3.1 are excluded: state
which transitive packages pull them in (e.g., make-dir@2.1.0, `@babel/`*,
istanbul-lib-instrument), why they must bypass trustPolicy: 'no-downgrade'
(e.g., blocking build or incompatible with newer semver semantics), and note
whether upgrading the parent dependencies to eliminate these versions was
evaluated and is feasible (or why it is not), so the exclusion rationale is
recorded next to the trustPolicyExclude entry.

---

Nitpick comments:
In `@testing/react-native-smoke/scripts/esbuild-smoke.ts`:
- Around line 14-20: Remove the forbidden root alias entry from the esbuild
alias map: delete the '`@tanstack/ai`': resolve(repoRoot,
'packages/ai/src/index.ts') line in the alias object in esbuild-smoke.ts so
imports must use the allowed scoped entry ('`@tanstack/ai/client`'); this aligns
with the import-surface rule that disallows importing from the '`@tanstack/ai`'
root.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60c0cd63-ed29-4403-a4c5-45d65705658a

📥 Commits

Reviewing files that changed from the base of the PR and between ef029a0 and be4108d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (78)
  • .changeset/react-native-ai-support.md
  • docs/advanced/tree-shaking.md
  • docs/api/ai-client.md
  • docs/api/ai-react.md
  • docs/chat/connection-adapters.md
  • docs/config.json
  • docs/getting-started/overview.md
  • docs/getting-started/quick-start-react-native.md
  • docs/getting-started/quick-start.md
  • docs/structured-outputs/multi-turn.md
  • examples/ts-react-native-chat/.gitignore
  • examples/ts-react-native-chat/README.md
  • examples/ts-react-native-chat/app.json
  • examples/ts-react-native-chat/index.ts
  • examples/ts-react-native-chat/metro.config.cjs
  • examples/ts-react-native-chat/package.json
  • examples/ts-react-native-chat/scripts/dev.mjs
  • examples/ts-react-native-chat/scripts/dev.test.mjs
  • examples/ts-react-native-chat/scripts/smoke-server.ts
  • examples/ts-react-native-chat/scripts/verify-react-resolution.mjs
  • examples/ts-react-native-chat/src/App.tsx
  • examples/ts-react-native-chat/src/server/app.ts
  • examples/ts-react-native-chat/src/server/index.ts
  • examples/ts-react-native-chat/tsconfig.json
  • package.json
  • packages/ai-client/src/chat-client.ts
  • packages/ai-client/src/connection-adapters.ts
  • packages/ai-client/src/events.ts
  • packages/ai-client/src/generation-client.ts
  • packages/ai-client/src/generation-types.ts
  • packages/ai-client/src/index.ts
  • packages/ai-client/src/realtime-client.ts
  • packages/ai-client/src/realtime-types.ts
  • packages/ai-client/src/response-stream.ts
  • packages/ai-client/src/sse-parser.ts
  • packages/ai-client/src/sse-utils.ts
  • packages/ai-client/src/tool-types.ts
  • packages/ai-client/src/types.ts
  • packages/ai-client/src/video-generation-client.ts
  • packages/ai-client/tests/chat-client-abort.test.ts
  • packages/ai-client/tests/chat-client.test.ts
  • packages/ai-client/tests/chat-fetcher.test.ts
  • packages/ai-client/tests/connection-adapters-abort.test.ts
  • packages/ai-client/tests/connection-adapters-xhr.test.ts
  • packages/ai-client/tests/connection-adapters.test.ts
  • packages/ai-client/tests/generation-client.test.ts
  • packages/ai-client/tests/infer-chat-messages.test.ts
  • packages/ai-client/tests/test-utils.ts
  • packages/ai-client/tests/tool-types.test.ts
  • packages/ai-client/tests/video-generation-client.test.ts
  • packages/ai-devtools/src/env.d.ts
  • packages/ai-devtools/tsconfig.json
  • packages/ai-preact/src/index.ts
  • packages/ai-react/src/index.ts
  • packages/ai-react/src/types.ts
  • packages/ai-react/src/use-chat.ts
  • packages/ai-solid/src/index.ts
  • packages/ai-svelte/src/index.ts
  • packages/ai-vue/src/index.ts
  • packages/ai/package.json
  • packages/ai/src/client.ts
  • packages/ai/vite.config.ts
  • packages/preact-ai-devtools/src/env.d.ts
  • packages/react-ai-devtools/src/env.d.ts
  • packages/solid-ai-devtools/src/env.d.ts
  • pnpm-workspace.yaml
  • testing/react-native-smoke/.gitignore
  • testing/react-native-smoke/README.md
  • testing/react-native-smoke/app.json
  • testing/react-native-smoke/index.ts
  • testing/react-native-smoke/metro.config.cjs
  • testing/react-native-smoke/package.json
  • testing/react-native-smoke/scripts/assert-bundle-output.ts
  • testing/react-native-smoke/scripts/assert-import-surface.ts
  • testing/react-native-smoke/scripts/esbuild-smoke.ts
  • testing/react-native-smoke/scripts/react-native-runtime-stub.tsx
  • testing/react-native-smoke/src/App.tsx
  • testing/react-native-smoke/tsconfig.json

Comment on lines +21 to 25
> **React Native or Expo app?** Use the headless React hooks with an absolute
> server URL and a mobile-compatible transport. See
> [Quick Start: React Native](./quick-start-react-native).

> **Tip:** If you'd prefer not to sign up with individual AI providers, [OpenRouter](../adapters/openrouter) gives you access to 300+ models with a single API key and is the easiest way to get started.
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix adjacent blockquote formatting to satisfy markdownlint (MD028).

The new React Native callout is separated from the next blockquote by a blank line, which triggers no-blanks-blockquote. Remove the blank line or merge the two callouts into one contiguous blockquote.

Suggested diff
 > **React Native or Expo app?** Use the headless React hooks with an absolute
 > server URL and a mobile-compatible transport. See
 > [Quick Start: React Native](./quick-start-react-native).
-
 > **Tip:** If you'd prefer not to sign up with individual AI providers, [OpenRouter](../adapters/openrouter) gives you access to 300+ models with a single API key and is the easiest way to get started.

As per coding guidelines: "**/*.{ts,tsx,js,jsx,json,md}: Use Prettier for code formatting".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
> **React Native or Expo app?** Use the headless React hooks with an absolute
> server URL and a mobile-compatible transport. See
> [Quick Start: React Native](./quick-start-react-native).
> **Tip:** If you'd prefer not to sign up with individual AI providers, [OpenRouter](../adapters/openrouter) gives you access to 300+ models with a single API key and is the easiest way to get started.
> **React Native or Expo app?** Use the headless React hooks with an absolute
> server URL and a mobile-compatible transport. See
> [Quick Start: React Native](./quick-start-react-native).
> **Tip:** If you'd prefer not to sign up with individual AI providers, [OpenRouter](../adapters/openrouter) gives you access to 300+ models with a single API key and is the easiest way to get started.
🧰 Tools
🪛 LanguageTool

[style] ~25-~25: Try using a synonym here to strengthen your writing.
Context: ...s, OpenRouter gives you access to 300+ models with a single API...

(GIVE_PROVIDE)

🪛 markdownlint-cli2 (0.22.1)

[warning] 24-24: Blank line inside blockquote

(MD028, no-blanks-blockquote)

🤖 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 `@docs/getting-started/quick-start.md` around lines 21 - 25, The two adjacent
blockquotes ("React Native or Expo app? Use the headless React hooks..." and the
"**Tip:** If you'd prefer not to sign up...") are separated by a blank line
which triggers markdownlint MD028; remove the empty line between them or merge
them into one contiguous blockquote so they form a single continuous blockquote
(locate the callout text starting with "React Native or Expo app?" and the
following "**Tip:**" paragraph and either delete the blank line or combine the
content into one blockquote).

Comment on lines +1 to +44
{
"name": "ts-react-native-chat",
"private": true,
"type": "module",
"main": "index.ts",
"expo": {
"install": {
"exclude": [
"@types/react",
"react",
"typescript"
]
}
},
"scripts": {
"dev": "node scripts/dev.mjs",
"dev:server": "tsx src/server/index.ts",
"dev:app": "node -e \"const { spawnSync } = require('node:child_process'); const env = { ...process.env, EXPO_NO_DOTENV: '1' }; delete env.OPENAI_API_KEY; delete env.OPENAI_MODEL; const args = ['exec', 'expo', 'start', '--lan', '--clear']; const result = process.platform === 'win32' ? spawnSync(env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', 'pnpm.cmd', ...args], { stdio: 'inherit', env }) : spawnSync('pnpm', args, { stdio: 'inherit', env }); process.exit(result.status ?? 1)\"",
"test:dev-script": "node --test scripts/dev.test.mjs",
"typecheck": "tsc --noEmit",
"smoke:server": "tsx scripts/smoke-server.ts",
"smoke:expo": "node -e \"const { spawnSync } = require('node:child_process'); const env = { ...process.env, EXPO_NO_DOTENV: '1' }; delete env.OPENAI_API_KEY; delete env.OPENAI_MODEL; const args = ['exec', 'expo', 'export', '--platform', 'ios', '--no-bytecode', '--output-dir', '.expo-example-dist', '--max-workers', '0']; const result = process.platform === 'win32' ? spawnSync(env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', 'pnpm.cmd', ...args], { stdio: 'inherit', env }) : spawnSync('pnpm', args, { stdio: 'inherit', env }); process.exit(result.status ?? 1)\"",
"verify:react-resolution": "node scripts/verify-react-resolution.mjs",
"smoke": "pnpm smoke:server && pnpm smoke:expo"
},
"dependencies": {
"@hono/node-server": "^1.19.6",
"@tanstack/ai": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
"@tanstack/ai-react": "workspace:*",
"concurrently": "^9.1.2",
"dotenv": "^17.2.3",
"expo": "~54.0.34",
"hono": "^4.10.6",
"react": "19.1.0",
"react-native": "0.81.5"
},
"devDependencies": {
"@types/node": "^24.10.1",
"@types/react": "19.1.17",
"tsx": "^4.21.0",
"typescript": "5.9.3"
}
}
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import json, pathlib
p = pathlib.Path("examples/ts-react-native-chat/package.json")
data = json.loads(p.read_text())
print("packageManager:", data.get("packageManager"))
PY

Repository: TanStack/ai

Length of output: 76


Add packageManager to this example manifest.

examples/ts-react-native-chat/package.json is missing packageManager: "pnpm@10.17.0" per the **/package.json coding guideline.

Proposed fix
 {
   "name": "ts-react-native-chat",
   "private": true,
+  "packageManager": "pnpm@10.17.0",
   "type": "module",
   "main": "index.ts",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
"name": "ts-react-native-chat",
"private": true,
"type": "module",
"main": "index.ts",
"expo": {
"install": {
"exclude": [
"@types/react",
"react",
"typescript"
]
}
},
"scripts": {
"dev": "node scripts/dev.mjs",
"dev:server": "tsx src/server/index.ts",
"dev:app": "node -e \"const { spawnSync } = require('node:child_process'); const env = { ...process.env, EXPO_NO_DOTENV: '1' }; delete env.OPENAI_API_KEY; delete env.OPENAI_MODEL; const args = ['exec', 'expo', 'start', '--lan', '--clear']; const result = process.platform === 'win32' ? spawnSync(env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', 'pnpm.cmd', ...args], { stdio: 'inherit', env }) : spawnSync('pnpm', args, { stdio: 'inherit', env }); process.exit(result.status ?? 1)\"",
"test:dev-script": "node --test scripts/dev.test.mjs",
"typecheck": "tsc --noEmit",
"smoke:server": "tsx scripts/smoke-server.ts",
"smoke:expo": "node -e \"const { spawnSync } = require('node:child_process'); const env = { ...process.env, EXPO_NO_DOTENV: '1' }; delete env.OPENAI_API_KEY; delete env.OPENAI_MODEL; const args = ['exec', 'expo', 'export', '--platform', 'ios', '--no-bytecode', '--output-dir', '.expo-example-dist', '--max-workers', '0']; const result = process.platform === 'win32' ? spawnSync(env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', 'pnpm.cmd', ...args], { stdio: 'inherit', env }) : spawnSync('pnpm', args, { stdio: 'inherit', env }); process.exit(result.status ?? 1)\"",
"verify:react-resolution": "node scripts/verify-react-resolution.mjs",
"smoke": "pnpm smoke:server && pnpm smoke:expo"
},
"dependencies": {
"@hono/node-server": "^1.19.6",
"@tanstack/ai": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
"@tanstack/ai-react": "workspace:*",
"concurrently": "^9.1.2",
"dotenv": "^17.2.3",
"expo": "~54.0.34",
"hono": "^4.10.6",
"react": "19.1.0",
"react-native": "0.81.5"
},
"devDependencies": {
"@types/node": "^24.10.1",
"@types/react": "19.1.17",
"tsx": "^4.21.0",
"typescript": "5.9.3"
}
}
{
"name": "ts-react-native-chat",
"private": true,
"packageManager": "pnpm@10.17.0",
"type": "module",
"main": "index.ts",
"expo": {
"install": {
"exclude": [
"`@types/react`",
"react",
"typescript"
]
}
},
"scripts": {
"dev": "node scripts/dev.mjs",
"dev:server": "tsx src/server/index.ts",
"dev:app": "node -e \"const { spawnSync } = require('node:child_process'); const env = { ...process.env, EXPO_NO_DOTENV: '1' }; delete env.OPENAI_API_KEY; delete env.OPENAI_MODEL; const args = ['exec', 'expo', 'start', '--lan', '--clear']; const result = process.platform === 'win32' ? spawnSync(env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', 'pnpm.cmd', ...args], { stdio: 'inherit', env }) : spawnSync('pnpm', args, { stdio: 'inherit', env }); process.exit(result.status ?? 1)\"",
"test:dev-script": "node --test scripts/dev.test.mjs",
"typecheck": "tsc --noEmit",
"smoke:server": "tsx scripts/smoke-server.ts",
"smoke:expo": "node -e \"const { spawnSync } = require('node:child_process'); const env = { ...process.env, EXPO_NO_DOTENV: '1' }; delete env.OPENAI_API_KEY; delete env.OPENAI_MODEL; const args = ['exec', 'expo', 'export', '--platform', 'ios', '--no-bytecode', '--output-dir', '.expo-example-dist', '--max-workers', '0']; const result = process.platform === 'win32' ? spawnSync(env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', 'pnpm.cmd', ...args], { stdio: 'inherit', env }) : spawnSync('pnpm', args, { stdio: 'inherit', env }); process.exit(result.status ?? 1)\"",
"verify:react-resolution": "node scripts/verify-react-resolution.mjs",
"smoke": "pnpm smoke:server && pnpm smoke:expo"
},
"dependencies": {
"`@hono/node-server`": "^1.19.6",
"`@tanstack/ai`": "workspace:*",
"`@tanstack/ai-openai`": "workspace:*",
"`@tanstack/ai-react`": "workspace:*",
"concurrently": "^9.1.2",
"dotenv": "^17.2.3",
"expo": "~54.0.34",
"hono": "^4.10.6",
"react": "19.1.0",
"react-native": "0.81.5"
},
"devDependencies": {
"`@types/node`": "^24.10.1",
"`@types/react`": "19.1.17",
"tsx": "^4.21.0",
"typescript": "5.9.3"
}
}
🤖 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 `@examples/ts-react-native-chat/package.json` around lines 1 - 44, Add the
missing packageManager field to the top-level package.json object in
examples/ts-react-native-chat by adding packageManager: "pnpm@10.17.0" (same
JSON object that contains "name", "private", "type", etc.); ensure the property
is a sibling to those keys so the package manifest follows the **/package.json
guideline.

Comment on lines +338 to +344
child.on('exit', (code, signal) => {
if (shuttingDown) return
if (code === 0 || signal) {
shutdown(0)
} else {
shutdown(code ?? 1)
}
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Don’t treat all signal-based child exits as success.

Line 340 currently maps any signal exit to code 0. If a child is terminated unexpectedly (for example SIGKILL), the runner still exits successfully and masks failure.

Suggested fix
     child.on('exit', (code, signal) => {
       if (shuttingDown) return
-      if (code === 0 || signal) {
+      if (code === 0) {
         shutdown(0)
+      } else if (signal === 'SIGINT' || signal === 'SIGTERM') {
+        shutdown(0)
       } else {
-        shutdown(code ?? 1)
+        shutdown(code ?? 1)
       }
     })
🤖 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 `@examples/ts-react-native-chat/scripts/dev.mjs` around lines 338 - 344, The
exit handler for child.on('exit') incorrectly treats any signal-based exit as
success; update the callback (the child.on('exit', (code, signal) => { ... })
block) so that if signal is non-null you call shutdown with a non-zero code
(e.g., shutdown(1) or shutdown with a code derived from the signal) instead of
shutdown(0), and include the signal in the shutdown invocation or log for
context; keep the existing shuttingDown guard and the existing success path for
code === 0 unchanged.


assert.equal(response.status, 200)
assert.ok(error)
assert.match(error.message, new RegExp(LIVE_RECIPE_SERVER_ERROR))
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use string matching instead of constructing a regex from message text.

Line 145 builds a RegExp from LIVE_RECIPE_SERVER_ERROR; metacharacters in the message can make this assertion flaky.

Suggested fix
-    assert.match(error.message, new RegExp(LIVE_RECIPE_SERVER_ERROR))
+    assert.ok(error.message.includes(LIVE_RECIPE_SERVER_ERROR))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert.match(error.message, new RegExp(LIVE_RECIPE_SERVER_ERROR))
assert.ok(error.message.includes(LIVE_RECIPE_SERVER_ERROR))
🤖 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 `@examples/ts-react-native-chat/scripts/smoke-server.ts` at line 145, The
assertion constructs a RegExp from LIVE_RECIPE_SERVER_ERROR which can
misinterpret regex metacharacters; change the check to a plain substring match
instead. Replace the call to assert.match(error.message, new
RegExp(LIVE_RECIPE_SERVER_ERROR)) with a string-based assertion such as
assert.include(error.message, LIVE_RECIPE_SERVER_ERROR) or
assert.ok(error.message.includes(LIVE_RECIPE_SERVER_ERROR)) so the test matches
the literal message text; keep references to LIVE_RECIPE_SERVER_ERROR and
error.message in the updated assertion.

})

assert.equal(response.status, 200)
assert.equal(response.headers.get('content-type'), 'application/x-ndjson')
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the content-type assertion tolerant of parameters.

Line 169 requires an exact value. Responses commonly include ; charset=utf-8, which would fail this smoke check unnecessarily.

Suggested fix
-  assert.equal(response.headers.get('content-type'), 'application/x-ndjson')
+  assert.ok(
+    response.headers.get('content-type')?.startsWith('application/x-ndjson'),
+  )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert.equal(response.headers.get('content-type'), 'application/x-ndjson')
assert.ok(
response.headers.get('content-type')?.startsWith('application/x-ndjson'),
)
🤖 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 `@examples/ts-react-native-chat/scripts/smoke-server.ts` at line 169, The
content-type assertion in smoke-server.ts compares the entire header string
exactly, which fails when parameters like "; charset=utf-8" are present; update
the assertion that calls response.headers.get('content-type') (the expression
used in the failing assert.equal) to instead check only the media type portion
or to test startsWith/includes (e.g., trim and split on ';' or use startsWith)
and use an appropriate assertion (assert.ok/assert.match) so the test accepts
"application/x-ndjson" with optional parameters.

Comment on lines +11 to +17
const port = Number.parseInt(process.env.PORT ?? '8787', 10)

serve({
fetch: app.fetch,
hostname: '0.0.0.0',
port,
})
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate PORT before passing it to serve.

Number.parseInt can return NaN for malformed env input, and passing that through can fail startup.

Proposed fix
-const port = Number.parseInt(process.env.PORT ?? '8787', 10)
+const parsedPort = Number.parseInt(process.env.PORT ?? '8787', 10)
+const port =
+  Number.isInteger(parsedPort) && parsedPort > 0 && parsedPort <= 65535
+    ? parsedPort
+    : 8787
🤖 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 `@examples/ts-react-native-chat/src/server/index.ts` around lines 11 - 17, The
PORT env value is parsed into port using Number.parseInt and may be NaN, which
can break the call to serve; update the initialization and before calling serve
to validate the parsed port (e.g., parse with Number.parseInt or Number(), then
check Number.isFinite/Number.isInteger and that port > 0 and within valid TCP
port range), and if invalid fall back to the default 8787 (or exit with a clear
error); make this change around the existing port variable and the serve({
fetch: app.fetch, hostname: '0.0.0.0', port }) invocation so serve always
receives a valid numeric port.

Comment thread pnpm-workspace.yaml
Comment on lines +6 to +7
trustPolicyExclude:
- 'semver@5.7.2 || 6.3.1'
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Analyze semver dependency tree to understand version conflicts

echo "=== Checking semver dependency tree ==="
pnpm why semver

echo -e "\n=== Checking for packages that depend on old semver versions ==="
pnpm list semver --depth=Infinity --long

echo -e "\n=== Checking if React Native packages are pulling in old semver ==="
rg -n 'semver.*5\.7\.2|semver.*6\.3\.1' --glob '**/package.json' -C2

Repository: TanStack/ai

Length of output: 50368


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== pnpm-workspace.yaml (lines around trustPolicy) ==="
nl -ba pnpm-workspace.yaml | sed -n '1,40p'

echo -e "\n=== pnpm why semver@5.7.2 (limit output) ==="
pnpm why semver@5.7.2 --depth 1 || true

echo -e "\n=== pnpm why semver@6.3.1 (limit output) ==="
pnpm why semver@6.3.1 --depth 1 || true

echo -e "\n=== Top-level dependents for semver@5.7.2 ==="
pnpm list --depth 0 semver@5.7.2 || true

echo -e "\n=== Top-level dependents for semver@6.3.1 ==="
pnpm list --depth 0 semver@6.3.1 || true

echo -e "\n=== Find exact entries of trustPolicyExclude in repo ==="
rg -n "trustPolicyExclude|trustPolicy:" -S pnpm-workspace.yaml **/pnpm-workspace.yaml **/*pnpm-workspace*.yaml || true

Repository: TanStack/ai

Length of output: 171


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== pnpm-workspace.yaml (lines around trustPolicy) ==="
cat -n pnpm-workspace.yaml | sed -n '1,80p'

echo -e "\n=== pnpm-workspace.yaml (grep trustPolicy*) ==="
rg -n "trustPolicy" pnpm-workspace.yaml || true

echo -e "\n=== pnpm why semver@5.7.2 (limit output) ==="
pnpm why semver@5.7.2 --depth 1 || true

echo -e "\n=== pnpm why semver@6.3.1 (limit output) ==="
pnpm why semver@6.3.1 --depth 1 || true

echo -e "\n=== Find exact entries of trustPolicyExclude in repo ==="
rg -n "trustPolicyExclude|trustPolicy:" -S pnpm-workspace.yaml **/pnpm-workspace*.yaml **/*pnpm*.yaml || true

Repository: TanStack/ai

Length of output: 2821


🌐 Web query:

pnpm trustPolicy no-downgrade trustPolicyExclude semantics

💡 Result:

The trustPolicy and trustPolicyExclude settings are supply chain security features in pnpm (introduced in v10.21.0 and v10.22.0, respectively) designed to mitigate risks from potentially compromised packages [1][2]. trustPolicy: no-downgrade When set to no-downgrade (default is off), pnpm checks the "trust level" of a package version against its history [1][2]. The trust levels are ordered: Trusted Publisher > Provenance > None [3]. If a package version has a lower trust level than any previously published version, pnpm will fail the installation [1][3]. These checks are based on the publication date, not semantic versioning [1]. Starting in v10.24.0, prerelease versions are ignored during this evaluation to prevent trusted prereleases from blocking stable releases that lack trust evidence [1]. trustPolicyExclude This setting (type: string[]) allows you to provide a list of package selectors to bypass the trustPolicy check [1][2]. This is useful for allowing specific, known-safe versions that do not meet the stricter trust requirements [1][2]. You can specify exact versions (e.g., 'chokidar@4.0.3'), version ranges (e.g., 'webpack@4.47.0 || 5.102.1'), or even exclude all versions of a package by omitting the version [1][4]. In summary, trustPolicy: no-downgrade enforces that trust evidence for a package never regresses, while trustPolicyExclude provides a necessary escape hatch for legitimate cases where downgrading the trust evidence is expected [1][3][2].

Citations:


Document and justify the trustPolicyExclude exception for semver

pnpm-workspace.yaml sets trustPolicy: 'no-downgrade' and excludes semver@5.7.2 || 6.3.1. Those semver versions come in transitively (semver@5.7.2 via make-dir@2.1.0; semver@6.3.1 via several @babel/* packages and istanbul-lib-instrument). Because no-downgrade is enforced on pnpm’s supply-chain “trust level” regression (not semver ordering), an exclusion can be a legitimate escape hatch—but it materially weakens the policy unless the rationale is recorded.

Add a short comment explaining why these specific versions must bypass no-downgrade (and whether upgrading the pulling deps to avoid them is feasible).

🤖 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 `@pnpm-workspace.yaml` around lines 6 - 7, Add an inline comment above the
trustPolicyExclude entry in pnpm-workspace.yaml explaining why semver@5.7.2 ||
6.3.1 are excluded: state which transitive packages pull them in (e.g.,
make-dir@2.1.0, `@babel/`*, istanbul-lib-instrument), why they must bypass
trustPolicy: 'no-downgrade' (e.g., blocking build or incompatible with newer
semver semantics), and note whether upgrading the parent dependencies to
eliminate these versions was evaluated and is feasible (or why it is not), so
the exclusion rationale is recorded next to the trustPolicyExclude entry.

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.

1 participant