Skip to content

Revert "Eliminate double JSON.stringify in RSC payload embedding (#2835)"#2878

Merged
justin808 merged 1 commit intomainfrom
jg-codex/revert-pr-2835
Mar 28, 2026
Merged

Revert "Eliminate double JSON.stringify in RSC payload embedding (#2835)"#2878
justin808 merged 1 commit intomainfrom
jg-codex/revert-pr-2835

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Mar 28, 2026

Summary

Why

Test Plan

  • Not run (pure git revert of previously reviewed code).

Note

Medium Risk
Touches Pro RSC streaming/hydration by changing how payload chunks are embedded, decoded, and replayed, which could reintroduce payload overhead and affect progressive hydration/stream correctness. Mostly a revert, but it alters client/server stream contracts and related tests.

Overview
Reverts the prior Pro RSC optimization that embedded parsed JSON payload objects directly into the HTML stream.

RSC payload injection now pushes stringified chunks into window.REACT_ON_RAILS_RSC_PAYLOADS again (with the client updated to expect string[]), and injectRSCPayload drops the NDJSON line-buffering/validation logic in favor of embedding each incoming stream chunk as-is.

Console replay handling is moved out of utils.ts (removing replayConsoleLog) and is performed inside transformRSCStreamAndReplayConsoleLogs, with tests and the changelog updated to reflect the revert.

Written by Cursor Bugbot for commit 123d474. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

Release Notes

  • Refactor
    • Simplified RSC payload serialization and stream processing logic
    • Consolidated console output handling for improved code maintainability
    • Reduced complexity in stream decoding and payload injection mechanisms

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cd3bea59-b4c5-4a00-8d09-2aa69e6f0fdf

📥 Commits

Reviewing files that changed from the base of the PR and between d1d8e6f and 123d474.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • packages/react-on-rails-pro/src/getReactServerComponent.client.ts
  • packages/react-on-rails-pro/src/injectRSCPayload.ts
  • packages/react-on-rails-pro/src/transformRSCStreamAndReplayConsoleLogs.ts
  • packages/react-on-rails-pro/src/utils.ts
  • packages/react-on-rails-pro/tests/RSCRequestTracker.test.ts
  • packages/react-on-rails-pro/tests/injectRSCPayload.test.ts
  • packages/react-on-rails-pro/tests/registerServerComponent.client.test.jsx

Walkthrough

This PR refactors RSC payload handling in react-on-rails-pro, changing from NDJSON line-based processing to per-chunk JSON serialization. Payloads transition from chunk objects to stringified representations, console replay moves inline, and the replayConsoleLog utility is removed. Tests updated accordingly.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md
Removed an "Unreleased → Performance" entry documenting elimination of double JSON.stringify during HTML RSC injection.
Payload Injection & Stream Processing
packages/react-on-rails-pro/src/injectRSCPayload.ts, packages/react-on-rails-pro/src/transformRSCStreamAndReplayConsoleLogs.ts
Refactored RSC payload serialization: replaced NDJSON line-buffering with per-chunk JSON.stringify() embedding; moved console replay logic inline; simplified stream decoding by removing incremental handling and end-of-stream incomplete-chunk processing.
Client-Side Payload Reconstruction
packages/react-on-rails-pro/src/getReactServerComponent.client.ts
Updated preloaded payload store type from Record<string, RSCPayloadChunk[]> to Record<string, string[]>; replaced direct stream construction with createRSCStreamFromArray(string[]) and centralized console replay via transformRSCStreamAndReplayConsoleLogs().
Utility Cleanup
packages/react-on-rails-pro/src/utils.ts
Removed exported replayConsoleLog() function; console script injection now handled inline in transformRSCStreamAndReplayConsoleLogs().
Integration Tests
packages/react-on-rails-pro/tests/RSCRequestTracker.test.ts
Updated assertions to verify payloads are embedded via JSON.stringify() instead of raw JSON objects.
Unit Tests
packages/react-on-rails-pro/tests/injectRSCPayload.test.ts, packages/react-on-rails-pro/tests/registerServerComponent.client.test.jsx
Adapted test fixtures and expectations: payloads now stringified (e.g., push("{...}") instead of push({...})); removed test cases covering NDJSON boundary splitting, UTF-8 edge cases, and malformed input error handling; fixture variables renamed for clarity.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Strings flow where objects once did dwell,
Per-chunk we stringify our RSC spell,
Console logs now whisper straight from the stream,
Simpler pathways fulfill our dream—
Payloads dance as text, not nested arrays,
A cleaner flow brightens all our days!

✨ 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 jg-codex/revert-pr-2835

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.

@justin808 justin808 merged commit 395fa1f into main Mar 28, 2026
29 of 30 checks passed
@justin808 justin808 deleted the jg-codex/revert-pr-2835 branch March 28, 2026 21:06
const finalChunk = (lastIncompleteLine + decoder.decode()).trim();
if (finalChunk !== '') {
const payloadScript = createRSCPayloadChunk(finalChunk, rscPayloadKey, sanitizedNonce);
const decodedChunk = typeof chunk === 'string' ? chunk : decoder.decode(chunk);
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.

Bug: TextDecoder reused without { stream: true } — will corrupt multibyte UTF-8 across chunk boundaries.

A single TextDecoder instance is created at line 91 and reused across every iteration of the for await loop. Without the { stream: true } option, the decoder flushes its internal buffer on every call, so a multibyte character (e.g. a 4-byte emoji or CJK codepoint) that is split across two consecutive binary chunks will be decoded as the replacement character U+FFFD in the first chunk and then corrupt the second.

Suggested change
const decodedChunk = typeof chunk === 'string' ? chunk : decoder.decode(chunk);
const decodedChunk = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });

The corresponding test ("handles chunks that split a multibyte UTF-8 character") was removed by this revert — it should be kept (or re-added in the follow-up PR) to guard this path.

try {
while (!done) {
const decodedValue = typeof value === 'string' ? value : decoder.decode(value, { stream: true });
const decodedValue = typeof value === 'string' ? value : decoder.decode(value);
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.

Same TextDecoder streaming bug as in injectRSCPayload.ts.

decoder.decode(value) without { stream: true } will mishandle a multibyte character split between two stream chunks.

Suggested change
const decodedValue = typeof value === 'string' ? value : decoder.decode(value);
const decodedValue = typeof value === 'string' ? value : decoder.decode(value, { stream: true });

parseAndHandleLines(finalDecodedValue.split('\n'));
}

controller.close();
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.

Silent data loss: the final incomplete NDJSON line is never flushed.

When the upstream stream ends, lastIncompleteChunk may still contain a valid NDJSON line that never ended with \n. The loop exits and controller.close() is called immediately, dropping that data silently.

PR #2835 fixed this by flushing after the loop:

const finalDecodedValue = lastIncompleteChunk + decoder.decode(); // flush remaining bytes
if (finalDecodedValue.trim() !== '') {
  parseAndHandleLines(finalDecodedValue.split('\n'));
}

This is a pre-existing regression worth carrying forward as a fix in the follow-up PR.

Comment on lines +227 to +228
expect(result).toContain('.push(');
expect(result).toContain(JSON.stringify(payload));
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.

Weakened assertion: the two toContain checks are independent and can match anywhere in the output.

The prior assertion expect(result).toContain(\.push(${payload})`)verified that the payload appeared as the argument to.push(in a single expression. Splitting it into two separate checks means the test passes even if.push(andJSON.stringify(payload)appear in completely different parts of the output (e.g. the payload in the HTML body and.push(` in an unrelated script tag).

Consider tightening it back to:

expect(result).toContain(`.push(${JSON.stringify(payload)})`);

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 123d474d0e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const finalChunk = (lastIncompleteLine + decoder.decode()).trim();
if (finalChunk !== '') {
const payloadScript = createRSCPayloadChunk(finalChunk, rscPayloadKey, sanitizedNonce);
const decodedChunk = typeof chunk === 'string' ? chunk : decoder.decode(chunk);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Decode RSC stream chunks with streaming TextDecoder

The RSC payload loop decodes each binary chunk with decoder.decode(chunk) (no { stream: true }), so a UTF-8 character split across chunk boundaries is replaced with U+FFFD before being embedded into <script> tags. This causes silent data corruption for non-ASCII/emoji content in Flight payloads, because the client only ever sees the already-corrupted string.

Useful? React with 👍 / 👎.

parseAndHandleLines(finalDecodedValue.split('\n'));
}

controller.close();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Parse buffered tail line before closing RSC transform

The transformer keeps partial NDJSON in lastIncompleteChunk, but on EOF it closes immediately without parsing that buffered remainder. When the final payload line does not end with \n, the last RSC chunk is dropped, which can leave hydration with incomplete Flight data (missing final UI chunk or unresolved suspense).

Useful? React with 👍 / 👎.

@github-actions
Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 62.63 KB (0%)
react-on-rails/client bundled (gzip) (time) 62.63 KB (0%)
react-on-rails/client bundled (brotli) 53.7 KB (0%)
react-on-rails/client bundled (brotli) (time) 53.7 KB (0%)
react-on-rails-pro/client bundled (gzip) 63.65 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 63.65 KB (0%)
react-on-rails-pro/client bundled (brotli) 54.67 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 54.67 KB (0%)
registerServerComponent/client bundled (gzip) 127.46 KB (0%)
registerServerComponent/client bundled (gzip) (time) 127.46 KB (0%)
registerServerComponent/client bundled (brotli) 61.65 KB (0%)
registerServerComponent/client bundled (brotli) (time) 61.65 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 122.02 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 122.02 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 56.77 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 56.77 KB (0%)

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 28, 2026

Review comment - see full text below

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 28, 2026

Review: Revert PR 2835

The revert itself is clean and the intent is clear. A few pre-existing bugs that PR 2835 had fixed are being re-introduced - worth tracking so the follow-up PR can address them explicitly.

Issues to carry forward in the follow-up PR

  1. TextDecoder reused without stream:true (two locations)

Both injectRSCPayload.ts (line 258) and transformRSCStreamAndReplayConsoleLogs.ts (line 67) share the same bug: a TextDecoder instance is constructed once and reused across iterations of an async loop, but each call uses decoder.decode(chunk) without { stream: true }. This flushes the decoder's internal buffer on every call, which corrupts any multibyte UTF-8 character (emoji, CJK, etc.) that happens to be split across two consecutive binary chunks. The fix is one word: decoder.decode(chunk, { stream: true }).

PR 2835 fixed this and included a dedicated test that is now removed by this revert.

  1. Final incomplete NDJSON line silently dropped in transformRSCStreamAndReplayConsoleLogs.ts

After the while loop exits, lastIncompleteChunk may still contain a valid payload line that never ended with a newline. The code jumps straight to controller.close() and the data is lost silently. PR 2835 flushed this buffer after the loop; the follow-up PR should restore that flush.

  1. Removed edge-case tests

This revert removes several correctness tests worth keeping regardless of the implementation approach: handles chunks that split across JSON object boundaries; handles chunks that split a multibyte UTF-8 character; normalizes CRLF on the final buffered payload chunk; emits an error instead of embedding malformed NDJSON as invalid JavaScript. These cover real streaming failure modes independent of whether the optimization from 2835 is in place.

  1. Weakened assertion in RSCRequestTracker.test.ts

The two separate toContain('.push(') and toContain(JSON.stringify(payload)) checks are weaker than the original single-expression check - they can pass even if the two strings appear in unrelated parts of the output. See inline comment.


The revert is appropriate and the PR description is clear. The items above are pre-existing regressions being restored; none block merging, but they should be in scope for the follow-up PR.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 28, 2026

Greptile Summary

This PR is a pure git revert of merge commit d1d8e6f9 (PR #2835 — "Eliminate double JSON.stringify in RSC payload embedding"), restoring main to the state before that optimization was landed. All source and test changes are mechanically correct inversions of what #2835 introduced.

Key changes (all intentional reversions):

  • injectRSCPayload.ts: Replaces NDJSON line-buffering + direct JSON expression embedding with JSON.stringify(chunk) per raw chunk; removes per-stream TextDecoder, reintroducing a shared decoder without { stream: true }.
  • transformRSCStreamAndReplayConsoleLogs.ts: Reverts to inline document.createElement for console replay and removes the post-loop flush of lastIncompleteChunk.
  • getReactServerComponent.client.ts: Reverts RSCPayloadChunk[] back to string[]; stream controller not closed when window is undefined.
  • utils.ts: replayConsoleLog helper removed.
  • Tests and CHANGELOG updated to match reverted behavior.

Known regressions reintroduced (track for follow-up PR):

  • Silent data loss when the last NDJSON line has no trailing newline.
  • Multi-byte UTF-8 corruption across chunk boundaries.
  • Hanging ReadableStream when window is undefined.
  • No document guard before document.createElement.

Confidence Score: 4/5

Safe to merge as an intentional revert, but reintroduces known P1 bugs that must be addressed in the follow-up PR before the feature lands again

The revert is mechanically correct. Three P1 regressions are reintroduced: silent NDJSON final-chunk data loss, UTF-8 multi-byte corruption across chunk boundaries, and a hanging ReadableStream in non-browser environments. These are pre-existing bugs being knowingly restored; merging is reasonable with eyes open if the team intends to fix them in a follow-up.

packages/react-on-rails-pro/src/transformRSCStreamAndReplayConsoleLogs.ts and packages/react-on-rails-pro/src/injectRSCPayload.ts contain the most impactful regressions

Important Files Changed

Filename Overview
packages/react-on-rails-pro/src/injectRSCPayload.ts Reverts NDJSON line-buffering and JSON expression embedding; reintroduces shared TextDecoder without { stream: true } across concurrent RSC streams
packages/react-on-rails-pro/src/transformRSCStreamAndReplayConsoleLogs.ts Reverts extracted replayConsoleLog helper and final-chunk flush; reintroduces silent data loss when last NDJSON line has no trailing newline
packages/react-on-rails-pro/src/getReactServerComponent.client.ts Reverts RSCPayloadChunk object stream back to plain string array; reintroduces hanging stream when controller is not closed in non-browser environments
packages/react-on-rails-pro/src/utils.ts Removes the replayConsoleLog helper extracted by PR #2835; clean revert with no new issues
packages/react-on-rails-pro/tests/injectRSCPayload.test.ts Removes UTF-8 boundary, CRLF, NDJSON cross-boundary, and malformed JSON test cases added by PR #2835; expected for this revert
packages/react-on-rails-pro/tests/RSCRequestTracker.test.ts Test assertion updated to expect JSON.stringify-wrapped payload strings instead of raw JSON expressions; consistent with reverted implementation
packages/react-on-rails-pro/tests/registerServerComponent.client.test.jsx Reverts test fixtures from parsed RSCPayloadChunk objects back to JSON-stringified strings; consistent with reverted implementation
CHANGELOG.md Removes the PR #2835 performance entry from the Unreleased section; correct and clean

Sequence Diagram

sequenceDiagram
    participant RSC as RSC Stream Node.js
    participant Inject as injectRSCPayload
    participant Browser as Browser
    participant GlobalArr as window RSC Payloads array
    participant Transform as transformRSCStream
    participant React as createFromReadableStream

    RSC->>Inject: raw chunk string or Buffer
    Note over Inject: decoder.decode no stream true flag
    Inject->>Inject: JSON.stringify decodedChunk
    Inject->>Browser: script tag pushing stringified chunk
    Browser->>GlobalArr: script executes pushes string
    GlobalArr->>Transform: string array via createRSCStreamFromArray
    Note over Transform: split by newline then JSON.parse each line
    Note over Transform: lastIncompleteChunk never flushed at end
    Transform->>React: Uint8Array html field of RSCPayloadChunk
    React-->>Browser: hydrated React tree
Loading

Reviews (1): Last reviewed commit: "Revert "Eliminate double JSON.stringify ..." | Re-trigger Greptile

Comment on lines 88 to 90
({ value, done } = await reader.read());
}

const finalDecodedValue = lastIncompleteChunk + decoder.decode();
if (finalDecodedValue.trim() !== '') {
parseAndHandleLines(finalDecodedValue.split('\n'));
}

controller.close();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Last incomplete chunk silently dropped

After the while (!done) loop ends, lastIncompleteChunk holds any data that was buffered from a line not yet terminated with \n. The loop calls controller.close() immediately without flushing this remaining buffer. If the RSC stream's final NDJSON line does not end with a newline, the data is silently lost.

PR #2835 fixed this by processing lastIncompleteChunk after the loop:

const finalDecodedValue = lastIncompleteChunk + decoder.decode();
if (finalDecodedValue.trim() !== '') {
  parseAndHandleLines(finalDecodedValue.split('\n'));
}

This is a known regression being reintroduced and should be tracked for the planned follow-up PR.

Comment on lines 97 to 100
start(controller) {
// Browser-only by design (callers read from window.REACT_ON_RAILS_RSC_PAYLOADS).
// If called outside the browser, close immediately to avoid hanging streams.
if (typeof window === 'undefined') {
closed = true;
controller.close();
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Stream controller never closed in non-browser environments

When typeof window === 'undefined', the start callback returns early without closing controller and without assigning streamController. The code executed after the new ReadableStream(...) constructor also silently no-ops because streamController is undefined. Any consumer reading from this stream will hang indefinitely. The version from PR #2835 explicitly called controller.close() in this branch. While this path is unlikely to be exercised in practice (callers guard on window.REACT_ON_RAILS_RSC_PAYLOADS), it is worth tracking for the follow-up PR.

const finalChunk = (lastIncompleteLine + decoder.decode()).trim();
if (finalChunk !== '') {
const payloadScript = createRSCPayloadChunk(finalChunk, rscPayloadKey, sanitizedNonce);
const decodedChunk = typeof chunk === 'string' ? chunk : decoder.decode(chunk);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 TextDecoder without { stream: true } corrupts multi-byte UTF-8 across chunk boundaries

decoder.decode(chunk) (without { stream: true }) signals to the TextDecoder that this is the final call, flushing its internal state. Any multi-byte UTF-8 sequence (e.g., emoji, CJK characters) that straddles two consecutive stream chunks will produce a replacement character (U+FFFD) instead of the correct code point.

PR #2835 fixed this with decoder.decode(chunk, { stream: true }) and also made the decoder local to each stream's IIFE so that concurrent streams don't share state. Both regressions are reintroduced here. The test case "handles chunks that split a multibyte UTF-8 character" was removed as part of this revert — worth noting for the follow-up PR.

Comment on lines +55 to 62
if (replayConsoleCode?.trim() !== '') {
const scriptElement = document.createElement('script');
if (sanitizedNonce) {
scriptElement.nonce = sanitizedNonce;
}
scriptElement.textContent = replayConsoleCode;
document.body.appendChild(scriptElement);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 document accessed without an SSR guard

document.createElement('script') is called here without first checking typeof document !== 'undefined'. The extracted replayConsoleLog helper in PR #2835's version of utils.ts carried an explicit guard:

if (typeof document === 'undefined') {
  return;
}

Although this code path lives in a .client.ts file and is unlikely to run in SSR, the defensive check is a best practice and prevents accidental crashes if the function is ever invoked in a Node.js context during testing or SSR. Worth restoring in the follow-up PR.

justin808 added a commit that referenced this pull request Mar 28, 2026
…ew-fixes

* origin/main:
  Remove dependency on internal TanStack Router router.ssr flag (#2833)
  Revert "Eliminate double JSON.stringify in RSC payload embedding (#2835)" (#2878)
  Eliminate double JSON.stringify in RSC payload embedding (#2835)
  docs: align Pro references with canonical docs routes (#2866)
  docs: make Pro route entry points explicit (#2867)
  Bump fastify from 5.8.1 to 5.8.3 in the npm-security group across 1 directory (#2846)
  docs: add RoR-specific competitive landscape and template refs (#2869)
  Clarify streaming narrative in RSC docs (#2813) (#2814)
justin808 added a commit that referenced this pull request Mar 29, 2026
…)" (#2878)

## Summary
- Reverts merge commit `d1d8e6f9` from PR #2835.
- Restores `main` to the state before "Eliminate double JSON.stringify
in RSC payload embedding".

## Why
- PR #2835 was merged accidentally and needs to be backed out.
- A fresh follow-up PR can be opened afterward with any remaining fixes.

## Test Plan
- Not run (pure git revert of previously reviewed code).

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches Pro RSC streaming/hydration by changing how payload chunks are
embedded, decoded, and replayed, which could reintroduce payload
overhead and affect progressive hydration/stream correctness. Mostly a
revert, but it alters client/server stream contracts and related tests.
> 
> **Overview**
> Reverts the prior Pro RSC optimization that embedded parsed JSON
payload objects directly into the HTML stream.
> 
> RSC payload injection now pushes **stringified chunks** into
`window.REACT_ON_RAILS_RSC_PAYLOADS` again (with the client updated to
expect `string[]`), and `injectRSCPayload` drops the NDJSON
line-buffering/validation logic in favor of embedding each incoming
stream chunk as-is.
> 
> Console replay handling is moved out of `utils.ts` (removing
`replayConsoleLog`) and is performed inside
`transformRSCStreamAndReplayConsoleLogs`, with tests and the changelog
updated to reflect the revert.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
123d474. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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