Skip to content

feat: add angular devtools support and fix core devtools reactivity#6248

Open
riccardoperra wants to merge 10 commits into
alphafrom
feat/angular-devtools
Open

feat: add angular devtools support and fix core devtools reactivity#6248
riccardoperra wants to merge 10 commits into
alphafrom
feat/angular-devtools

Conversation

@riccardoperra
Copy link
Copy Markdown
Collaborator

@riccardoperra riccardoperra commented May 9, 2026

TanStack Devtools Angular package is not published yet in npm

  • add new @tanstack/angular-table-devtools package
  • add devtools integration in composable tables

Summary by CodeRabbit

  • New Features
    • Added TanStack DevTools integration to Angular and React examples, enabling interactive debugging and monitoring of table state, columns, rows, and options in development mode.
    • Introduced new Angular Table DevTools package with automatic environment detection for seamless devtools registration.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

📝 Walkthrough

Walkthrough

This PR introduces TanStack Table Devtools across Angular and React frameworks by creating a new Angular devtools package, integrating devtools into 20+ Angular examples, adding React table instance ID tracking, enhancing React devtools, and refactoring the core table-devtools module to use Solid reactivity.

Changes

Angular Table Devtools Package and Examples

Layer / File(s) Summary
Angular Table Devtools Package Creation
packages/angular-table-devtools/package.json, packages/angular-table-devtools/tsconfig.json, packages/angular-table-devtools/tsdown.config.ts, packages/angular-table-devtools/vite.config.ts, packages/angular-table-devtools/eslint.config.js
New @tanstack/angular-table-devtools package with build configuration, TypeScript setup, Vitest and ESLint integration.
Angular Devtools Panel and DI Integration
packages/angular-table-devtools/src/TableDevtools.ts, packages/angular-table-devtools/src/injectTanStackTableDevtools.ts, packages/angular-table-devtools/src/plugin.ts, packages/angular-table-devtools/src/index.ts, packages/angular-table-devtools/src/production.ts
Devtools panel component with Angular init types, DI-aware injection function managing lifecycle via Angular DestroyRef and effects, plugin factory, and conditional dev/no-op exports based on isDevMode().
Angular Examples Devtools Integration
examples/angular/*/package.json, examples/angular/*/src/app/app.config.ts, examples/angular/*/src/app/app.ts, examples/angular/composable-tables/src/app/components/*/\.ts
Consistent pattern applied across 20+ Angular examples: add @tanstack/angular-devtools and @tanstack/angular-table-devtools dependencies, conditionally provide devtools via provideTanStackDevtools() when isDevMode() is true with lazy-loaded TableDevtoolsPanel, and inject devtools in component constructors using injectTanStackTableDevtools().

React Table Devtools Support

Layer / File(s) Summary
React Table Instance ID Support
packages/react-table/src/useTable.ts
Extend ReactTable type with optional instanceId?: string; implement ref-backed UUID generation per hook instance using globalThis.crypto.randomUUID() with fallback to incrementing counter.
React Devtools Hook Refactor
packages/react-table-devtools/src/useTanStackTableDevtools.ts
Update hook to compute normalized name and stable instanceId from table adapter or useId()\-based fallback; refactor useEffect to register/unregister devtools targets by instanceId instead of registrationId.
React Example Devtools Integration
examples/react/composable-tables/package.json, examples/react/composable-tables/src/main.tsx
Add @tanstack/react-devtools and @tanstack/react-table-devtools to devDependencies; import and register useTanStackTableDevtools hook for both Users and Products tables; render TanStackDevtools component with tableDevtoolsPlugin().

Table Devtools Solid Reactivity Migration

Layer / File(s) Summary
Store and Registration Reactivity
packages/table-devtools/src/useTableStore.ts, packages/table-devtools/src/tableTarget.ts, packages/table-devtools/src/TableContextProvider.tsx
Refactor useTableStore to accept Solid accessor to store instead of store object; convert tableTarget registration storage from imperative Map + listeners to Solid signal with effect-based subscriptions; update AnyTable type constraint and initialize selectedTargetId from computed initialTargets.
Simple Panel Reactivity Updates
packages/table-devtools/src/components/ColumnsPanel.tsx, packages/table-devtools/src/components/OptionsPanel.tsx
Refactor to use useTableStore with createMemo for derived column and option state; replace early returns with Solid Show components and NoTableConnected fallbacks.
Complex Panel Reactivity Refactors
packages/table-devtools/src/components/FeaturesPanel.tsx, packages/table-devtools/src/components/RowsPanel.tsx, packages/table-devtools/src/components/StatePanel.tsx
Replace eager computation and conditional subscriptions with Solid createMemo and createEffect to reactively derive features, rows, state slices, and available row models; update getRowCountForModel to accept optional table and guard function access; render via Show with NoTableConnected fallbacks and For loops over memoized data.
Shell and Styling Updates
packages/table-devtools/src/components/Shell.tsx, packages/table-devtools/src/components/ThreeWayResizableSplit.tsx, packages/table-devtools/eslint.config.js, packages/table-devtools/package.json
Update Shell to use Solid Show render props and For loops; add eslint-disable-next-line solid/reactivity directive; add eslint-plugin-solid to devDependencies and update ESLint config to use Solid's recommended rules.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • schiller-manuel
  • KevinVandy

Poem

🐰 Behold the devtools dawn, where tables come alive!
From Angular to React, the integrations thrive.
With Solid's reactive grace, old patterns fade away,
A symphony of instance IDs and signals here to stay. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add angular devtools support and fix core devtools reactivity' directly aligns with the PR's main objectives: adding Angular devtools support (@tanstack/angular-table-devtools package) and fixing devtools state reactivity in core.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feat/angular-devtools

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.

@riccardoperra riccardoperra changed the title feat: add angular devtools feat: integrate angular devtools May 9, 2026
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 9, 2026

View your CI Pipeline Execution ↗ for commit 8a240a5

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ✅ Succeeded 47s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 1s View ↗

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 9, 2026

More templates

@tanstack/angular-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/angular-table@6248

@tanstack/angular-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/angular-table-devtools@6248

@tanstack/lit-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/lit-table@6248

@tanstack/match-sorter-utils

npm i https://pkg.pr.new/TanStack/table/@tanstack/match-sorter-utils@6248

@tanstack/preact-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/preact-table@6248

@tanstack/preact-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/preact-table-devtools@6248

@tanstack/react-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/react-table@6248

@tanstack/react-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/react-table-devtools@6248

@tanstack/solid-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/solid-table@6248

@tanstack/solid-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/solid-table-devtools@6248

@tanstack/svelte-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/svelte-table@6248

@tanstack/table-core

npm i https://pkg.pr.new/TanStack/table/@tanstack/table-core@6248

@tanstack/table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/table-devtools@6248

@tanstack/vue-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/vue-table@6248

@tanstack/vue-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/vue-table-devtools@6248

commit: 8a240a5

Copy link
Copy Markdown

@nx-cloud nx-cloud Bot left a comment

Choose a reason for hiding this comment

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

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud is proposing a fix for your failed CI:

We resolved two CI failures introduced by the angular devtools integration. The sherif failure was fixed by reordering dependencies alphabetically in the composable-tables example, and the knip failures were fixed by removing the unused @tanstack/angular-devtools dependency from the package, adding the missing tslib dependency required by importHelpers, and removing the export keyword from the internal-only generateId function.

Tip

We verified this fix by re-running table:test:sherif, table:test:knip.

Suggested Fix changes
diff --git a/examples/angular/composable-tables/package.json b/examples/angular/composable-tables/package.json
index 2663831d..3d441290 100644
--- a/examples/angular/composable-tables/package.json
+++ b/examples/angular/composable-tables/package.json
@@ -19,8 +19,8 @@
     "@angular/router": "^21.2.11",
     "@faker-js/faker": "^10.4.0",
     "@tanstack/angular-devtools": "https://pkg.pr.new/TanStack/devtools/@tanstack/angular-devtools@368",
-    "@tanstack/angular-table-devtools": "^9.0.0-alpha.43",
     "@tanstack/angular-table": "^9.0.0-alpha.45",
+    "@tanstack/angular-table-devtools": "^9.0.0-alpha.43",
     "rxjs": "~7.8.2",
     "tslib": "^2.8.1"
   },
diff --git a/packages/angular-table-devtools/package.json b/packages/angular-table-devtools/package.json
index 7bf1bf22..2df42e78 100644
--- a/packages/angular-table-devtools/package.json
+++ b/packages/angular-table-devtools/package.json
@@ -44,10 +44,10 @@
     "src"
   ],
   "dependencies": {
-    "@tanstack/angular-devtools": "https://pkg.pr.new/TanStack/devtools/@tanstack/angular-devtools@368",
     "@tanstack/devtools-utils": "https://pkg.pr.new/TanStack/devtools/@tanstack/devtools-utils@368",
     "@tanstack/table-core": "workspace:*",
-    "@tanstack/table-devtools": "workspace:*"
+    "@tanstack/table-devtools": "workspace:*",
+    "tslib": "^2.8.1"
   },
   "peerDependencies": {
     "@angular/core": ">=21.0.0"
diff --git a/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts b/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts
index 40303e30..e769ae3b 100644
--- a/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts
+++ b/packages/angular-table-devtools/src/injectTanStackTableDevtools.ts
@@ -24,7 +24,7 @@ function normalizeName(name?: string) {
 }
 
 let autoId = 0
-export function generateId(): string {
+function generateId(): string {
   const appId = inject(APP_ID)
   return `tanstacktable-${appId}_${autoId++}${Date.now().toString(36)}`
 }

Apply fix via Nx Cloud  Reject fix via Nx Cloud


Or Apply changes locally with:

npx nx-cloud apply-locally DsIG-vU7o

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

@riccardoperra riccardoperra force-pushed the feat/angular-devtools branch 2 times, most recently from 9a3e490 to d397a99 Compare May 9, 2026 08:05
@riccardoperra riccardoperra changed the title feat: integrate angular devtools feat(angular): integrate angular devtools May 9, 2026
@riccardoperra riccardoperra force-pushed the feat/angular-devtools branch 2 times, most recently from 5b002f3 to 926dcf9 Compare May 17, 2026 12:21
@riccardoperra riccardoperra changed the title feat(angular): integrate angular devtools feat: add angular devtools support and fix core devtools reactivity May 19, 2026
@riccardoperra riccardoperra force-pushed the feat/angular-devtools branch from 17bc739 to cd854d6 Compare May 19, 2026 13:24
Refactor devtools panel with a more solid-idiomatic approach, using memo and dynamic `useTableState` subscription via Accessor getter to not break reactivity.
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 19, 2026

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 19, 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
High CVE: npm @angular/platform-server: SSRF via Hostname Hijacking

CVE: GHSA-rfh7-fxqc-q52v @angular/platform-server: SSRF via Hostname Hijacking (HIGH)

Affected versions: >= 22.0.0-next.0 < 22.0.0-next.12; >= 21.0.0-next.0 < 21.2.13; >= 20.0.0-next.0 < 20.3.21; >= 19.0.0-next.0 < 19.2.22; <= 18.2.14

Patched version: 21.2.13

From: examples/angular/remote-data/package.jsonnpm/@angular/platform-server@21.2.12

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

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: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@angular/platform-server@21.2.12. 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

@riccardoperra riccardoperra force-pushed the feat/angular-devtools branch from 2967e10 to 20b40f9 Compare May 19, 2026 13:30
@riccardoperra riccardoperra force-pushed the feat/angular-devtools branch from 20b40f9 to bdd89ba Compare May 19, 2026 13:35
Comment thread packages/react-table/src/useTable.ts Outdated
@@ -137,6 +141,12 @@ export function useTable<
tableOptions: TableOptions<TFeatures, TData>,
selector?: (state: TableState<TFeatures>) => TSelected,
): ReactTable<TFeatures, TData, TSelected> {
const instanceIdRef = useRef<string | undefined>(undefined)
const id = useId()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this technically makes this a React 18+ package now. We could just require an id/key table option in order for devtools to work, and then remove the 2nd arg from useTanStackTableDevtools(table)

Copy link
Copy Markdown
Collaborator Author

@riccardoperra riccardoperra May 19, 2026

Choose a reason for hiding this comment

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

What about removing entirely useId 🤔 ? There is still the generation logic provided next. it was just added as a prefix but probably unnecessary

-  const id = useId()
   if (!instanceIdRef.current) {
    // eslint-disable-next-line @eslint-react/purity
-     instanceIdRef.current = `${id}-${Math.random().toString(36).slice(2, 9)}`
+     instanceIdRef.current = Math.random().toString(36).slice(2, 9);
   }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Using math.random for anything in a library usually causes security scanners to freak out, even if it's for something trivial like this.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

switched with crypto.randomUUID (if present) or just id++ for this

@KevinVandy KevinVandy marked this pull request as ready for review May 21, 2026 23:10
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: 6

🧹 Nitpick comments (4)
packages/table-devtools/src/components/StatePanel.tsx (1)

1-1: 💤 Low value

Unused import: createEffect.

createEffect is imported but not used in this file.

🧹 Proposed fix
-import { For, Show, createEffect, createMemo, createSignal } from 'solid-js'
+import { For, Show, createMemo, createSignal } from 'solid-js'
🤖 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/table-devtools/src/components/StatePanel.tsx` at line 1, Remove the
unused Solid import createEffect from the import list in StatePanel.tsx; update
the import line that currently reads import { For, Show, createEffect,
createMemo, createSignal } from 'solid-js' to omit createEffect so only used
symbols (For, Show, createMemo, createSignal) remain, ensuring no other
references to createEffect exist in the file before committing.
packages/table-devtools/src/useTableStore.ts (1)

5-9: 💤 Low value

Outdated documentation.

The comment still claims the hook handles both subscribe APIs (function return for 0.8.x and { unsubscribe } for 0.9.x), but the implementation now only handles the { unsubscribe } object return pattern on line 28.

📝 Proposed fix
 /**
- * Subscribes to a table store and returns a reactive signal.
- * Handles both subscribe APIs: function return (store 0.8.x) and
- * { unsubscribe } object return (store 0.9.x).
+ * Subscribes to a table store and returns a reactive signal.
  */
🤖 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/table-devtools/src/useTableStore.ts` around lines 5 - 9, The
docblock for useTableStore is outdated: it claims support for both the old
function-return subscribe API and the new { unsubscribe } object-return API, but
the implementation only handles the object-return pattern; update the comment
above useTableStore to state that the hook expects the { unsubscribe }
object-return subscription API (remove the mention of the function-return 0.8.x
pattern) so the documentation matches the actual behavior of the subscribe
handling in useTableStore.
packages/table-devtools/src/components/ThreeWayResizableSplit.tsx (1)

23-23: ⚡ Quick win

Document the ESLint suppression rationale.

The suppression is likely justified since event handlers in Solid can read signals without tracking, but adding a brief comment would help future maintainers understand why the rule was disabled.

📝 Suggested documentation
-    // eslint-disable-next-line solid/reactivity
+    // eslint-disable-next-line solid/reactivity -- Event handlers can read signals without tracking
     (e) => {
🤖 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/table-devtools/src/components/ThreeWayResizableSplit.tsx` at line
23, Add a short rationale comment immediately above the existing eslint
suppression for the solid/reactivity rule in ThreeWayResizableSplit (where "//
eslint-disable-next-line solid/reactivity" appears) explaining why the rule is
disabled (e.g., event handlers intentionally read signals without tracking to
avoid creating reactive subscriptions and to prevent unnecessary rerenders).
Reference the component name ThreeWayResizableSplit and the specific suppression
so maintainers understand this is intentional and safe for the event-handler
context.
examples/angular/row-selection-signal/src/app/app.config.ts (1)

6-20: ⚡ Quick win

Provider array creates nested array in production builds.

The ternary expression isDevMode() ? provideTanStackDevtools(...) : [] produces [[]] (an array containing an empty array) when dev mode is false. While Angular may tolerate this, it's structurally incorrect.

♻️ Use spread operator to flatten conditional providers
 export const appConfig: ApplicationConfig = {
   providers: [
-    isDevMode()
-      ? provideTanStackDevtools(() => ({
-          plugins: [
-            {
-              name: 'TanStack Table',
-              render: () =>
-                import('`@tanstack/angular-table-devtools`').then((m) =>
-                  m.TableDevtoolsPanel(),
-                ),
-            },
-          ],
-        }))
-      : [],
+    ...(isDevMode()
+      ? [provideTanStackDevtools(() => ({
+          plugins: [
+            {
+              name: 'TanStack Table',
+              render: () =>
+                import('`@tanstack/angular-table-devtools`').then((m) =>
+                  m.TableDevtoolsPanel(),
+                ),
+            },
+          ],
+        }))]
+      : []),
   ],
 }

Note: This pattern appears across all Angular example app.config.ts files in this PR. Consider applying the fix consistently.

🤖 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/angular/row-selection-signal/src/app/app.config.ts` around lines 6 -
20, The providers array conditionally returns an array (or empty array) causing
a nested array ([[]]) in production; update the providers entry to spread the
conditional result so it flattens into the outer array—e.g., replace the current
ternary `isDevMode() ? provideTanStackDevtools(...) : []` with `...(isDevMode()
? [provideTanStackDevtools(() => ({ plugins: [...] }))] : [])` (referencing
isDevMode and provideTanStackDevtools and the existing devtools plugin block)
and apply the same pattern across other app.config.ts examples.
🤖 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 `@examples/angular/row-selection-signal/package.json`:
- Line 14: Dependencies for Angular in package.json are inconsistent: update the
downgraded packages (e.g., "`@angular/animations`" and any other Angular packages
currently at "^21.2.12") to the same version used by the rest ("^21.2.13") so
all `@angular/`* entries use a single, consistent version spec; edit the
dependency entries in package.json to replace "^21.2.12" with "^21.2.13" for the
identified Angular package names.

In `@packages/angular-table-devtools/src/injectTanStackTableDevtools.ts`:
- Around line 46-53: The code currently calls
removeTableDevtoolsTarget(registrationId) when enabledValue is falsy or table is
missing but then continues to call upsertTableDevtoolsTarget(...) which
re-registers the target (possibly with an undefined table); update the branch so
that when !enabledValue || !table the function returns early (or otherwise skips
the subsequent upsert) instead of falling through, ensuring
removeTableDevtoolsTarget(registrationId) is the terminal action for that case
and only call upsertTableDevtoolsTarget with { id: registrationId, table, name:
normalizeName(name) } when enabledValue is truthy and table exists.

In `@packages/react-table-devtools/src/useTanStackTableDevtools.ts`:
- Around line 38-54: The effect that registers the devtools target (useEffect)
omits normalizedName from its dependency array, so changes to name won't trigger
upsertTableDevtoolsTarget when instanceId is stable; update the dependency list
for the useEffect that calls upsertTableDevtoolsTarget/removeTableDevtoolsTarget
to include normalizedName alongside enabled, registrationId, and instanceId so
the effect reruns and existingRegistration.name is updated when normalizedName
changes.
- Around line 31-34: The computed instanceId is evaluated unguarded and can
throw when table is undefined, and normalizedName changes are not propagated
because it isn’t in the effect dependencies; inside useTanStackTableDevtools
(function name) move the computation of instanceId into the useEffect that
guards on table (or guard before accessing (table as ...).instanceId) and add
normalizedName to the effect dependency array so instanceId is recomputed when
name changes; ensure the upsertTableDevtoolsTarget call uses the locally
computed instanceId and the current normalizedName so updates propagate
correctly.

In `@packages/react-table/src/useTable.ts`:
- Around line 145-150: The current check "'randomUUID' in globalThis.crypto" can
throw if globalThis.crypto is undefined; update the guard around instanceIdRef
initialization (in useTable) to safely check for crypto and randomUUID — e.g.,
verify globalThis.crypto exists and has a randomUUID function (like typeof
globalThis.crypto?.randomUUID === 'function' or 'randomUUID' in
(globalThis.crypto || {})) before calling it, falling back to the
`table-${++tableId}` path if not available; reference instanceIdRef, useRef,
globalThis.crypto.randomUUID and tableId when making the change.

In `@packages/table-devtools/src/components/Shell.tsx`:
- Around line 52-65: The render-prop parameters passed into Solid's Show are
already resolved values, not accessors—fix the JSX in the Show children to treat
the parameters as values: when destructuring the first Show use the value (e.g.,
tableOptions) as the options prop (options={tableOptions}), and in the inner
Show use the value (e.g., selectedTargetId) as the Select value
(value={selectedTargetId}) and call setSelectedTargetId from the onChange
handler; ensure you still call the accessors tableOptions() and
selectedTargetId() only where you intend to read the signals directly, and
reference Show, tableOptions, selectedTargetId, setSelectedTargetId, Select, and
EMPTY_PANEL_KEY to locate the incorrect props.

---

Nitpick comments:
In `@examples/angular/row-selection-signal/src/app/app.config.ts`:
- Around line 6-20: The providers array conditionally returns an array (or empty
array) causing a nested array ([[]]) in production; update the providers entry
to spread the conditional result so it flattens into the outer array—e.g.,
replace the current ternary `isDevMode() ? provideTanStackDevtools(...) : []`
with `...(isDevMode() ? [provideTanStackDevtools(() => ({ plugins: [...] }))] :
[])` (referencing isDevMode and provideTanStackDevtools and the existing
devtools plugin block) and apply the same pattern across other app.config.ts
examples.

In `@packages/table-devtools/src/components/StatePanel.tsx`:
- Line 1: Remove the unused Solid import createEffect from the import list in
StatePanel.tsx; update the import line that currently reads import { For, Show,
createEffect, createMemo, createSignal } from 'solid-js' to omit createEffect so
only used symbols (For, Show, createMemo, createSignal) remain, ensuring no
other references to createEffect exist in the file before committing.

In `@packages/table-devtools/src/components/ThreeWayResizableSplit.tsx`:
- Line 23: Add a short rationale comment immediately above the existing eslint
suppression for the solid/reactivity rule in ThreeWayResizableSplit (where "//
eslint-disable-next-line solid/reactivity" appears) explaining why the rule is
disabled (e.g., event handlers intentionally read signals without tracking to
avoid creating reactive subscriptions and to prevent unnecessary rerenders).
Reference the component name ThreeWayResizableSplit and the specific suppression
so maintainers understand this is intentional and safe for the event-handler
context.

In `@packages/table-devtools/src/useTableStore.ts`:
- Around line 5-9: The docblock for useTableStore is outdated: it claims support
for both the old function-return subscribe API and the new { unsubscribe }
object-return API, but the implementation only handles the object-return
pattern; update the comment above useTableStore to state that the hook expects
the { unsubscribe } object-return subscription API (remove the mention of the
function-return 0.8.x pattern) so the documentation matches the actual behavior
of the subscribe handling in useTableStore.
🪄 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: 7181463f-b364-476b-8721-90df11ac2ddc

📥 Commits

Reviewing files that changed from the base of the PR and between 4db9f8e and 8a240a5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (84)
  • examples/angular/basic-app-table/package.json
  • examples/angular/basic-app-table/src/app/app.config.ts
  • examples/angular/basic-app-table/src/app/app.ts
  • examples/angular/basic-inject-table/package.json
  • examples/angular/basic-inject-table/src/app/app.config.ts
  • examples/angular/basic-inject-table/src/app/app.ts
  • examples/angular/column-ordering/package.json
  • examples/angular/column-ordering/src/app/app.config.ts
  • examples/angular/column-ordering/src/app/app.ts
  • examples/angular/column-pinning-sticky/package.json
  • examples/angular/column-pinning-sticky/src/app/app.config.ts
  • examples/angular/column-pinning-sticky/src/app/app.ts
  • examples/angular/column-pinning/package.json
  • examples/angular/column-pinning/src/app/app.config.ts
  • examples/angular/column-pinning/src/app/app.ts
  • examples/angular/column-resizing-performant/package.json
  • examples/angular/column-resizing-performant/src/app/app.config.ts
  • examples/angular/column-resizing-performant/src/app/app.ts
  • examples/angular/column-visibility/package.json
  • examples/angular/column-visibility/src/app/app.config.ts
  • examples/angular/column-visibility/src/app/app.ts
  • examples/angular/composable-tables/package.json
  • examples/angular/composable-tables/src/app/app.config.ts
  • examples/angular/composable-tables/src/app/components/products-table/products-table.ts
  • examples/angular/composable-tables/src/app/components/users-table/users-table.ts
  • examples/angular/custom-plugin/package.json
  • examples/angular/custom-plugin/src/app/app.config.ts
  • examples/angular/custom-plugin/src/app/app.ts
  • examples/angular/editable/package.json
  • examples/angular/editable/src/app/app.config.ts
  • examples/angular/editable/src/app/app.ts
  • examples/angular/expanding/package.json
  • examples/angular/expanding/src/app/app.config.ts
  • examples/angular/expanding/src/app/app.ts
  • examples/angular/filters/package.json
  • examples/angular/filters/src/app/app.config.ts
  • examples/angular/filters/src/app/app.ts
  • examples/angular/grouping/package.json
  • examples/angular/grouping/src/app/app.config.ts
  • examples/angular/grouping/src/app/app.ts
  • examples/angular/remote-data/package.json
  • examples/angular/remote-data/src/app/app.config.ts
  • examples/angular/remote-data/src/app/app.ts
  • examples/angular/row-dnd/package.json
  • examples/angular/row-dnd/src/app/app.config.ts
  • examples/angular/row-dnd/src/app/app.ts
  • examples/angular/row-selection-signal/package.json
  • examples/angular/row-selection-signal/src/app/app.component.ts
  • examples/angular/row-selection-signal/src/app/app.config.ts
  • examples/angular/row-selection/package.json
  • examples/angular/row-selection/src/app/app.config.ts
  • examples/angular/row-selection/src/app/app.ts
  • examples/angular/signal-input/package.json
  • examples/angular/signal-input/src/app/app.config.ts
  • examples/angular/signal-input/src/app/person-table/person-table.ts
  • examples/angular/sub-components/package.json
  • examples/angular/sub-components/src/app/app.config.ts
  • examples/angular/sub-components/src/app/app.ts
  • examples/react/composable-tables/package.json
  • examples/react/composable-tables/src/main.tsx
  • packages/angular-table-devtools/eslint.config.js
  • packages/angular-table-devtools/package.json
  • packages/angular-table-devtools/src/TableDevtools.ts
  • packages/angular-table-devtools/src/index.ts
  • packages/angular-table-devtools/src/injectTanStackTableDevtools.ts
  • packages/angular-table-devtools/src/plugin.ts
  • packages/angular-table-devtools/src/production.ts
  • packages/angular-table-devtools/tsconfig.json
  • packages/angular-table-devtools/tsdown.config.ts
  • packages/angular-table-devtools/vite.config.ts
  • packages/react-table-devtools/src/useTanStackTableDevtools.ts
  • packages/react-table/src/useTable.ts
  • packages/table-devtools/eslint.config.js
  • packages/table-devtools/package.json
  • packages/table-devtools/src/TableContextProvider.tsx
  • packages/table-devtools/src/components/ColumnsPanel.tsx
  • packages/table-devtools/src/components/FeaturesPanel.tsx
  • packages/table-devtools/src/components/OptionsPanel.tsx
  • packages/table-devtools/src/components/RowsPanel.tsx
  • packages/table-devtools/src/components/Shell.tsx
  • packages/table-devtools/src/components/StatePanel.tsx
  • packages/table-devtools/src/components/ThreeWayResizableSplit.tsx
  • packages/table-devtools/src/tableTarget.ts
  • packages/table-devtools/src/useTableStore.ts

"private": true,
"dependencies": {
"@angular/animations": "^21.2.13",
"@angular/animations": "^21.2.12",
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

Inconsistent Angular package versions.

Two Angular packages are downgraded to 21.2.12 while the rest remain at 21.2.13 (lines 15-19). This version mismatch can cause peer dependency warnings and potential runtime issues.

📦 Align Angular package versions
-    "`@angular/animations`": "^21.2.12",
+    "`@angular/animations`": "^21.2.13",
-    "`@angular/platform-browser-dynamic`": "^21.2.12",
+    "`@angular/platform-browser-dynamic`": "^21.2.13",

Also applies to: 20-20

🤖 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/angular/row-selection-signal/package.json` at line 14, Dependencies
for Angular in package.json are inconsistent: update the downgraded packages
(e.g., "`@angular/animations`" and any other Angular packages currently at
"^21.2.12") to the same version used by the rest ("^21.2.13") so all `@angular/`*
entries use a single, consistent version spec; edit the dependency entries in
package.json to replace "^21.2.12" with "^21.2.13" for the identified Angular
package names.

Comment on lines +46 to +53
if (!enabledValue || !table) {
removeTableDevtoolsTarget(registrationId)
}
upsertTableDevtoolsTarget({
id: registrationId,
table: table,
name: normalizeName(name),
})
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

Stop upserting after the disabled/no-table branch.

Lines 46-53 remove the target but then still re-register it. This makes enabled ineffective and can register an undefined table.

Proposed fix
       const { table, name } = options()
       const enabledValue = enabled()
       if (!enabledValue || !table) {
         removeTableDevtoolsTarget(registrationId)
+        return
       }
       upsertTableDevtoolsTarget({
         id: registrationId,
         table: table,
         name: normalizeName(name),
       })
📝 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
if (!enabledValue || !table) {
removeTableDevtoolsTarget(registrationId)
}
upsertTableDevtoolsTarget({
id: registrationId,
table: table,
name: normalizeName(name),
})
if (!enabledValue || !table) {
removeTableDevtoolsTarget(registrationId)
return
}
upsertTableDevtoolsTarget({
id: registrationId,
table: table,
name: normalizeName(name),
})
🤖 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/angular-table-devtools/src/injectTanStackTableDevtools.ts` around
lines 46 - 53, The code currently calls
removeTableDevtoolsTarget(registrationId) when enabledValue is falsy or table is
missing but then continues to call upsertTableDevtoolsTarget(...) which
re-registers the target (possibly with an undefined table); update the branch so
that when !enabledValue || !table the function returns early (or otherwise skips
the subsequent upsert) instead of falling through, ensuring
removeTableDevtoolsTarget(registrationId) is the terminal action for that case
and only call upsertTableDevtoolsTarget with { id: registrationId, table, name:
normalizeName(name) } when enabledValue is truthy and table exists.

Comment on lines +31 to +34
const instanceId =
// instanceId from react table adapter (if it exists) allows for stable devtools registration even if the table instance changes
(table as unknown as { instanceId?: string }).instanceId ||
`${registrationId}${normalizedName ? `-${normalizedName}` : ``}`
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 | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/react-table-devtools/src/useTanStackTableDevtools.ts"
if [ ! -f "$FILE" ]; then
  echo "File not found: $FILE" >&2
  exit 1
fi

# Show the relevant lines with context (keep output small)
nl -ba "$FILE" | sed -n '1,120p' | sed -n '20,90p'

Repository: TanStack/table

Length of output: 102


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/react-table-devtools/src/useTanStackTableDevtools.ts"
test -f "$FILE" || { echo "File not found: $FILE" >&2; exit 1; }

# Print only the relevant section (around the reported line range)
# Use cat -n (available) instead of nl.
cat -n "$FILE" | sed -n '1,120p' | sed -n '20,90p'

echo "-----"

# Also extract just the `instanceId` assignment block and the nearest effect deps
rg -n "instanceId\s*=" "$FILE" -n
rg -n "useEffect\(|upsertTableDevtoolsTarget|normalizedName|enabled|registrationId" "$FILE" -n

Repository: TanStack/table

Length of output: 2180


Fix potential runtime crash in instanceId and ensure normalizedName updates propagate

  • Critical: instanceId is computed outside the useEffect guard; when table is undefined, (table ...).instanceId can throw before the if (!table) check runs.
  • Minor: normalizedName is used in upsertTableDevtoolsTarget({ name: normalizedName }), but it’s not in the effect deps; if table.instanceId is present, instanceId won’t change when name changes, so updates may not propagate.
🐛 Suggested fix
-  const instanceId =
-    // instanceId from react table adapter (if it exists) allows for stable devtools registration even if the table instance changes
-    (table as unknown as { instanceId?: string }).instanceId ||
-    `${registrationId}${normalizedName ? `-${normalizedName}` : ``}`
+  const instanceId =
+    // instanceId from react table adapter (if it exists) allows for stable devtools registration even if the table instance changes
+    (table as { instanceId?: string } | undefined)?.instanceId ??
+    `${registrationId}${normalizedName ? `-${normalizedName}` : ``}`
📝 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
const instanceId =
// instanceId from react table adapter (if it exists) allows for stable devtools registration even if the table instance changes
(table as unknown as { instanceId?: string }).instanceId ||
`${registrationId}${normalizedName ? `-${normalizedName}` : ``}`
const instanceId =
// instanceId from react table adapter (if it exists) allows for stable devtools registration even if the table instance changes
(table as { instanceId?: string } | undefined)?.instanceId ??
`${registrationId}${normalizedName ? `-${normalizedName}` : ``}`
🤖 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/react-table-devtools/src/useTanStackTableDevtools.ts` around lines
31 - 34, The computed instanceId is evaluated unguarded and can throw when table
is undefined, and normalizedName changes are not propagated because it isn’t in
the effect dependencies; inside useTanStackTableDevtools (function name) move
the computation of instanceId into the useEffect that guards on table (or guard
before accessing (table as ...).instanceId) and add normalizedName to the effect
dependency array so instanceId is recomputed when name changes; ensure the
upsertTableDevtoolsTarget call uses the locally computed instanceId and the
current normalizedName so updates propagate correctly.

Comment on lines +38 to +54
useEffect(() => {
if (!enabled || !table) {
removeTableDevtoolsTarget(registrationId)
removeTableDevtoolsTarget(instanceId)
return
}

upsertTableDevtoolsTarget({
id: registrationId,
id: instanceId,
table,
name: normalizeName(name),
name: normalizedName,
})

return () => {
removeTableDevtoolsTarget(registrationId)
removeTableDevtoolsTarget(instanceId)
}
}, [enabled, name, registrationId, table])
// eslint-disable-next-line @eslint-react/exhaustive-deps,react-hooks/exhaustive-deps
}, [enabled, registrationId, instanceId])
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
set -euo pipefail

FILE="packages/react-table-devtools/src/useTanStackTableDevtools.ts"

echo "=== File header (imports/exports) ==="
sed -n '1,120p' "$FILE" | nl -ba

echo "=== Target effect region (lines ~30-80) ==="
sed -n '1,120p' "$FILE" | nl -ba | sed -n '25,90p'

echo "=== Search for normalizedName definition/usages ==="
rg -n "normalizedName" "$FILE" || true

echo "=== Locate upsertTableDevtoolsTarget/removeTableDevtoolsTarget implementations ==="
rg -n "function upsertTableDevtoolsTarget|upsertTableDevtoolsTarget\\(|removeTableDevtoolsTarget\\(" packages/react-table-devtools -S

# Also search whole repo in case helpers live elsewhere
rg -n "upsertTableDevtoolsTarget\\(|removeTableDevtoolsTarget\\(" -S

Repository: TanStack/table

Length of output: 157


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/react-table-devtools/src/useTanStackTableDevtools.ts"

echo "=== Show lines 1-140 with line numbers (python) ==="
python3 - <<'PY'
path = "packages/react-table-devtools/src/useTanStackTableDevtools.ts"
with open(path, "r", encoding="utf-8") as f:
    for i, line in enumerate(f, 1):
        if i <= 140:
            print(f"{i:4d}: {line.rstrip()}")
PY

echo "=== Search normalizedName definition/usages ==="
rg -n "normalizedName" "$FILE" || true

echo "=== Search for upsert/remove helpers ==="
rg -n "upsertTableDevtoolsTarget\\(|removeTableDevtoolsTarget\\(" -S packages/react-table-devtools || true
rg -n "upsertTableDevtoolsTarget\\(|removeTableDevtoolsTarget\\(" -S . || true

Repository: TanStack/table

Length of output: 6144


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/table-devtools/src/tableTarget.ts"
python3 - <<'PY'
path = "packages/table-devtools/src/tableTarget.ts"
with open(path, "r", encoding="utf-8") as f:
    for i, line in enumerate(f, 1):
        if i <= 200:
            print(f"{i:4d}: {line.rstrip()}")
PY

echo "=== Search for 'name' usage inside tableTarget.ts ==="
rg -n "name\\b" packages/table-devtools/src/tableTarget.ts

Repository: TanStack/table

Length of output: 3057


Add normalizedName to the effect deps so devtools target name updates when adapter instanceId is stable.

normalizedName is sent to upsertTableDevtoolsTarget, but it isn’t in the useEffect deps; when the adapter provides a stable instanceId, changing name won’t rerun the effect, so existingRegistration.name won’t be updated.

♻️ Suggested fix
-  }, [enabled, registrationId, instanceId])
+  }, [enabled, registrationId, instanceId, normalizedName])
📝 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
useEffect(() => {
if (!enabled || !table) {
removeTableDevtoolsTarget(registrationId)
removeTableDevtoolsTarget(instanceId)
return
}
upsertTableDevtoolsTarget({
id: registrationId,
id: instanceId,
table,
name: normalizeName(name),
name: normalizedName,
})
return () => {
removeTableDevtoolsTarget(registrationId)
removeTableDevtoolsTarget(instanceId)
}
}, [enabled, name, registrationId, table])
// eslint-disable-next-line @eslint-react/exhaustive-deps,react-hooks/exhaustive-deps
}, [enabled, registrationId, instanceId])
useEffect(() => {
if (!enabled || !table) {
removeTableDevtoolsTarget(instanceId)
return
}
upsertTableDevtoolsTarget({
id: instanceId,
table,
name: normalizedName,
})
return () => {
removeTableDevtoolsTarget(instanceId)
}
// eslint-disable-next-line `@eslint-react/exhaustive-deps`,react-hooks/exhaustive-deps
}, [enabled, registrationId, instanceId, normalizedName])
🤖 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/react-table-devtools/src/useTanStackTableDevtools.ts` around lines
38 - 54, The effect that registers the devtools target (useEffect) omits
normalizedName from its dependency array, so changes to name won't trigger
upsertTableDevtoolsTarget when instanceId is stable; update the dependency list
for the useEffect that calls upsertTableDevtoolsTarget/removeTableDevtoolsTarget
to include normalizedName alongside enabled, registrationId, and instanceId so
the effect reruns and existingRegistration.name is updated when normalizedName
changes.

Comment on lines +145 to +150
const instanceIdRef = useRef<string | undefined>(undefined)
if (!instanceIdRef.current) {
instanceIdRef.current =
'randomUUID' in globalThis.crypto
? globalThis.crypto.randomUUID()
: `table-${++tableId}`
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
set -euo pipefail

# Locate the file and print the relevant region with line numbers
FILE="packages/react-table/src/useTable.ts"
if [ ! -f "$FILE" ]; then
  echo "Missing file: $FILE" >&2
  exit 1
fi

echo "---- $FILE (lines ~120-180) ----"
nl -ba "$FILE" | sed -n '120,190p'

# Search for other uses/guards of globalThis.crypto / randomUUID in the codebase
echo "---- Search: globalThis.crypto / randomUUID ----"
rg -n "globalThis\.crypto|randomUUID" packages/react-table/src || true

# Check whether there's any polyfill/assumption about globalThis.crypto earlier in repo
echo "---- Search: randomUUID in repo (small scope) ----"
rg -n "randomUUID" packages/react-table || true

Repository: TanStack/table

Length of output: 184


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/react-table/src/useTable.ts"
if [ ! -f "$FILE" ]; then
  echo "Missing file: $FILE" >&2
  exit 1
fi

python3 - <<'PY'
from pathlib import Path
path = Path("packages/react-table/src/useTable.ts")
lines = path.read_text(encoding="utf-8").splitlines()
start, end = 120, 190  # 1-based line numbers
for i in range(start, min(end, len(lines)) + 1):
    print(f"{i:4d}\t{lines[i-1]}")
PY

echo "---- Search: globalThis.crypto / randomUUID ----"
rg -n "globalThis\.crypto|randomUUID" packages/react-table/src || true

echo "---- Search: crypto polyfills / globalThis assumptions (small scope) ----"
rg -n "globalThis|crypto" packages/react-table || true

Repository: TanStack/table

Length of output: 2655


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- Search entire repo for globalThis.crypto / randomUUID ----"
rg -n "globalThis\.crypto|randomUUID" . || true

echo "---- Search for crypto polyfills or globalThis assignments ----"
rg -n "polyfill|crypto\.randomUUID|require\\('crypto'\\)|globalThis\\.(crypto|msCrypto)" . || true

echo "---- Search for checks like 'crypto' in globalThis ----"
rg -n "'crypto' in globalThis|globalThis\\.crypto\\s*\\?|typeof globalThis\\.crypto" . || true

Repository: TanStack/table

Length of output: 4887


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show root package engines / browserslist (if any)
ls -la package.json >/dev/null 2>&1 && cat package.json || true
echo "----"
for f in packages/*/package.json packages/react-table/package.json; do
  if [ -f "$f" ]; then echo "## $f"; cat "$f"; fi
done

echo "---- Search for browserslist / engines ----"
rg -n "\"browserslist\"|browserslist|\"engines\"" -S . || true

Repository: TanStack/table

Length of output: 34086


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- Search for useTable usage in react-table package ----"
rg -n "useTable\\(" packages/react-table || true

echo "---- Search for react-table test setup (jsdom/node) ----"
rg -n "jsdom|testEnvironment|vitest.*environment|environment:" packages/react-table packages/table-core packages/react-table-devtools || true

echo "---- Search README for SSR / crypto assumptions ----"
for f in packages/react-table/README.md packages/react-table-devtools/README.md README.md; do
  if [ -f "$f" ]; then
    echo "## $f"
    rg -n "SSR|server|hydrate|crypto|randomUUID" "$f" || true
  fi
done

Repository: TanStack/table

Length of output: 10044


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- packages/react-table/vite.config.ts ----"
cat packages/react-table/vite.config.ts

echo "---- packages/react-table-devtools/vite.config.ts ----"
cat packages/react-table-devtools/vite.config.ts 2>/dev/null || true

echo "---- packages/table-core/vite.config.ts ----"
cat packages/table-core/vite.config.ts 2>/dev/null || true

echo "---- Search for vitest config in react-table ----"
rg -n "vitest|environment\\s*:\\s*'jsdom'|test\\s*:\\s*\\{|jsdom" packages/react-table -S || true

echo "---- Search for SSR notes in useTable docs/comments ----"
rg -n "server-side|SSR|hydrate|globalThis" packages/react-table/src -S || true

Repository: TanStack/table

Length of output: 1668


🏁 Script executed:

node -p "({ crypto: typeof globalThis.crypto, randomUUID: typeof globalThis.crypto?.randomUUID })"

Repository: TanStack/table

Length of output: 103


🌐 Web query:

Node 16 globalThis.crypto availability webcrypto experimental global webcrypto

💡 Result:

In Node.js 16, Web Crypto is available via the Web Crypto API implementation, but it is not exposed as globalThis.crypto; you should use require('node:crypto').webcrypto (CommonJS) or import { webcrypto } from 'node:crypto' (ESM) instead.[1][2] What to do in Node 16: 1) CommonJS const { webcrypto } = require('node:crypto'); const { subtle } = webcrypto; 2) ESM import { webcrypto } from 'node:crypto'; const { subtle } = webcrypto; For contrast: current Node.js docs (e.g., newer versions) describe accessing the same Web Crypto API via globalThis.crypto or require('node:crypto').webcrypto.[3][4] Notes: - Node’s Web Crypto API is implemented as the standard Web Crypto API, with globalThis.crypto being an instance of the Crypto singleton in environments where it’s available.[3][4]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "globalThis\\.crypto|randomUUID" packages/react-table/src || true

Repository: TanStack/table

Length of output: 221


Guard globalThis.crypto before probing randomUUID.

'randomUUID' in globalThis.crypto throws a TypeError when globalThis.crypto is missing (possible in Node 16 SSR/server runtimes since @tanstack/react-table supports node >=16). Use a guarded check for randomUUID instead.

🐛 Suggested fix
   if (!instanceIdRef.current) {
-    instanceIdRef.current =
-      'randomUUID' in globalThis.crypto
-        ? globalThis.crypto.randomUUID()
-        : `table-${++tableId}`
+    const cryptoObj = globalThis.crypto
+    instanceIdRef.current =
+      typeof cryptoObj?.randomUUID === 'function'
+        ? cryptoObj.randomUUID()
+        : `table-${++tableId}`
   }
🤖 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/react-table/src/useTable.ts` around lines 145 - 150, The current
check "'randomUUID' in globalThis.crypto" can throw if globalThis.crypto is
undefined; update the guard around instanceIdRef initialization (in useTable) to
safely check for crypto and randomUUID — e.g., verify globalThis.crypto exists
and has a randomUUID function (like typeof globalThis.crypto?.randomUUID ===
'function' or 'randomUUID' in (globalThis.crypto || {})) before calling it,
falling back to the `table-${++tableId}` path if not available; reference
instanceIdRef, useRef, globalThis.crypto.randomUUID and tableId when making the
change.

Comment on lines +52 to 65
<Show when={tableOptions().length > 0 && tableOptions()}>
{(tableOptions) => (
<Show when={selectedTargetId() ?? EMPTY_PANEL_KEY}>
{(selectedTargetId) => (
<Select
label="Table"
options={tableOptions()}
value={selectedTargetId()}
onChange={(value) => setSelectedTargetId(value)}
/>
)}
</Show>
)}
</Show>
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 | 🔴 Critical | ⚡ Quick win

Critical: Render prop parameters are values, not functions.

Solid's Show render prop receives the resolved value, not an accessor function. Lines 58-59 incorrectly call the render prop parameters as functions:

  • Line 53: (tableOptions) receives the array returned by tableOptions()
  • Line 58: options={tableOptions()} attempts to call that array as a function ❌
  • Line 55: (selectedTargetId) receives the string/value
  • Line 59: value={selectedTargetId()} attempts to call that value as a function ❌

This will cause a TypeError: ... is not a function at runtime.

🐛 Proposed fix
         <Show when={tableOptions().length > 0 && tableOptions()}>
           {(tableOptions) => (
             <Show when={selectedTargetId() ?? EMPTY_PANEL_KEY}>
               {(selectedTargetId) => (
                 <Select
                   label="Table"
-                  options={tableOptions()}
-                  value={selectedTargetId()}
+                  options={tableOptions}
+                  value={selectedTargetId}
                   onChange={(value) => setSelectedTargetId(value)}
                 />
               )}
             </Show>
           )}
         </Show>
📝 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
<Show when={tableOptions().length > 0 && tableOptions()}>
{(tableOptions) => (
<Show when={selectedTargetId() ?? EMPTY_PANEL_KEY}>
{(selectedTargetId) => (
<Select
label="Table"
options={tableOptions()}
value={selectedTargetId()}
onChange={(value) => setSelectedTargetId(value)}
/>
)}
</Show>
)}
</Show>
<Show when={tableOptions().length > 0 && tableOptions()}>
{(tableOptions) => (
<Show when={selectedTargetId() ?? EMPTY_PANEL_KEY}>
{(selectedTargetId) => (
<Select
label="Table"
options={tableOptions}
value={selectedTargetId}
onChange={(value) => setSelectedTargetId(value)}
/>
)}
</Show>
)}
</Show>
🤖 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/table-devtools/src/components/Shell.tsx` around lines 52 - 65, The
render-prop parameters passed into Solid's Show are already resolved values, not
accessors—fix the JSX in the Show children to treat the parameters as values:
when destructuring the first Show use the value (e.g., tableOptions) as the
options prop (options={tableOptions}), and in the inner Show use the value
(e.g., selectedTargetId) as the Select value (value={selectedTargetId}) and call
setSelectedTargetId from the onChange handler; ensure you still call the
accessors tableOptions() and selectedTargetId() only where you intend to read
the signals directly, and reference Show, tableOptions, selectedTargetId,
setSelectedTargetId, Select, and EMPTY_PANEL_KEY to locate the incorrect props.

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.

2 participants