Skip to content

fix(tables): SSR crash from tableKeys in a 'use client' module + drop redundant flushChunks#5204

Merged
waleedlatif1 merged 3 commits into
stagingfrom
fix/tables-querykey-ssr
Jun 25, 2026
Merged

fix(tables): SSR crash from tableKeys in a 'use client' module + drop redundant flushChunks#5204
waleedlatif1 merged 3 commits into
stagingfrom
fix/tables-querykey-ssr

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Two fixes, both off staging:

1. Tables list crash at SSR (regression from #5196)

The tables list page failed to load in staging with:

TypeError: i.tableKeys.list is not a function
  (In 'i.tableKeys.list(b, "active")', 'i.tableKeys.list' is undefined)
  at .next/server/chunks/ssr/[root-of-the-server]

Cause: tables/prefetch.ts is a server component, but it imported tableKeys from hooks/queries/tables.ts, which carries 'use client'. When a server module imports from a 'use client' module, Next.js replaces the export with a client-reference stub in the server bundle — so tableKeys.list is undefined at SSR. (The other three prefetch pages were fine because their key factories live in non-'use client' modules, e.g. folder-keys.ts.)

Fix: Extract the key factory into hooks/queries/utils/table-keys.ts (no 'use client'), mirroring the existing folder-keys.ts pattern, and import it from there in the prefetch, the hook, the table trigger/poller, and the two consumers. tables.ts now imports the factory instead of defining it.

2. Redundant flushChunks() on the SSE error path (chat.tsx)

Addresses a Greptile P2 from the release PR. On an error final event the reader stops (return true), so the post-loop flush is the single flush point. Defer the error append to after that flush — single flush, correct ordering — instead of flushing inside onEvent and again post-loop. No behavior change.

Type of Change

  • Bug fix (SSR crash) + minor refactor

Testing

  • prefetch.test.ts (9 tests) green; tsc 0 errors; Biome clean; check:react-query passes.
  • The SSR fix mirrors the proven folder-keys.ts pattern (pure non-'use client' module); CI's "Test and Build" exercises the real next build/SSR path.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)
@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 25, 2026 12:31am

Request Review

@cursor

cursor Bot commented Jun 25, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Targeted SSR import split and small SSE/chat ordering fixes; keys are unchanged and tests cover the new SSE tail behavior.

Overview
Fixes a staging SSR crash on the tables list (tableKeys.list is not a function) by moving the React Query key factory out of hooks/queries/tables.ts into a new hooks/queries/utils/table-keys.ts (no 'use client'), matching folder-keys.ts. Server prefetch and other callers now import the real factory instead of a Next.js client-reference stub.

Workflow chat streaming: failed final SSE events no longer call flushChunks() inside onEvent; the error is stored and appended after the post-loop flush so chunk batching stays single-flush.

SSE reader: readSSELines now decodes and processes the last partial line when the stream ends (final data: without a trailing newline), with new tests for stream-tail and multi-byte UTF-8 cases.

Reviewed by Cursor Bugbot for commit dc1cf47. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two independent regressions introduced in #5196: an SSR crash caused by importing tableKeys from a 'use client' module in a server component, and a silent data-loss bug in readSSELines that dropped the final SSE line when it lacked a trailing newline.

  • SSR crash fix: tableKeys and TableQueryScope are extracted into a new hooks/queries/utils/table-keys.ts (no 'use client'), mirroring folder-keys.ts. All five consumers updated to import from the new location.
  • SSE decoder fix: readSSELines now flushes the TextDecoder and processes the final unterminated line when done=true. Two new tests cover a plain single-line tail and a split multi-byte character.
  • Chat error path cleanup: The redundant flushChunks() inside onEvent is removed; the error append is deferred until after the single post-loop flush.

Confidence Score: 5/5

Safe to merge — both fixes are narrowly scoped, mechanically correct, and backed by new tests.

The table-keys.ts extraction is a pure refactor with no logic changes; TypeScript enforces that all consumers updated correctly. The readSSELines change is a targeted loop-order fix with two purpose-built tests that directly exercise the previously broken path. The chat error deferral eliminates a double-flush with no observable behavior change.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/hooks/queries/utils/table-keys.ts New standalone non-use-client key factory, an exact mirror of the removed definition in tables.ts
apps/sim/lib/core/utils/sse.ts Fixes readSSELines to flush the TextDecoder and process the final unterminated SSE line instead of silently dropping it when done=true
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx Defers error message append to after the single post-loop flushChunks(), eliminating the redundant in-event flush
apps/sim/app/workspace/[workspaceId]/tables/prefetch.ts Import updated from use-client tables.ts to the new standalone table-keys.ts, fixing the SSR crash
apps/sim/hooks/queries/tables.ts Removed tableKeys definition and TableQueryScope type, now imported from utils/table-keys.ts; no logic changes

Reviews (2): Last reviewed commit: "fix(sse): process the final unterminated..." | Re-trigger Greptile

…h works

The tables list page crashed at SSR ('tableKeys.list is not a function') because
tables/prefetch.ts (a server component) imported tableKeys from
hooks/queries/tables.ts — a 'use client' module whose exports resolve to
client-reference stubs on the server. Extract the key factory into
hooks/queries/utils/table-keys.ts (no 'use client'), mirroring folder-keys.ts,
and import it from there in the prefetch, hook, trigger, and consumers.
On an error 'final' event the reader stops via return true, so the post-loop
flush is the single flush point. Defer the error append to after that flush
(single flush, correct ordering) instead of flushing inside onEvent and again
post-loop. No behavior change.
readSSELines broke out of the read loop on 'done' without flushing the
TextDecoder or processing the trailing buffer, so a final 'data:' line not
terminated by a newline (and any buffered multi-byte character) was dropped.
Flush the decoder on end-of-stream and process the remaining buffer.
Addresses a Cursor Medium finding on the consolidated SSE reader.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit dc1cf47. Configure here.

@waleedlatif1 waleedlatif1 merged commit c3a0969 into staging Jun 25, 2026
16 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/tables-querykey-ssr branch June 25, 2026 00:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant