Wang1rrr opened a new issue, #4774:
URL: https://github.com/apache/rocketmq-dashboard/issues/4774
### Before Creating the Bug Report
- [x] I searched open and closed issues/PRs and believe this is not a
duplicate.
- [x] This concerns RocketMQ Studio, not another RocketMQ repository.
- [x] The exact inspected version and reproduction scope are stated below.
### Studio Version
- Branch: `rocketmq-studio`
- Commit: `4c697f07acde460e2344375cb1f82669f5b270fd`
- Reproduction: source-function probe, not a deployed Studio instance.
### Runtime Environment
Windows, Node.js `v22.23.2`. The probe executes the checked-in formatter and
download
handler, with Node's real `Blob` and an in-memory replacement for
`downloadBlob`.
No browser or MySQL instance was involved.
### Connected RocketMQ Cluster
None. A synthetic `MessageRecord.body` string is sufficient to reproduce this
client-side transformation; no broker or customer data is needed.
### Describe the Bug
The ordinary message-page download handler runs `record.body` through
`formatBody`
before creating the JSON Blob. That formatter calls `JSON.parse` followed by
`JSON.stringify`, so JSON integers outside JavaScript's safe integer range
can be
silently changed in the downloaded content.
For example, the incoming body string `{"orderId":9007199254740993}`
produces a
download containing `9007199254740992`. The incoming field is already a
string;
this particular precision loss happens inside the UI formatter, not while
decoding
the outer HTTP response.
### Steps to Reproduce
From a checkout of the commit above, save this as a temporary `.mjs` file
and run
it with Node.js 22.23.2, using the repository root as the working directory:
```js
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { stripTypeScriptTypes } from 'node:module';
import vm from 'node:vm';
const source = readFileSync('web/src/pages/instance/message.tsx', 'utf8');
const formatter = source.match(
/^const formatBody = \(body: string\): string => \{[\s\S]*?^\};/m,
)?.[0];
const handler = source.match(
/^ const handleDownload = \(record: MessageRecord\) => \{[\s\S]*?^ \};/m,
)?.[0];
assert.ok(formatter && handler, 'Source changed: inspect the two functions
first');
let captured;
const context = vm.createContext({
Blob,
downloadBlob: (blob) => { captured = blob; },
message: { success: () => {} },
t: (key) => key,
});
vm.runInContext(stripTypeScriptTypes(
`${formatter}\n${handler}\nglobalThis.download = handleDownload;`,
), context, { timeout: 1000 });
const record = { msgId: 'precision-repro', body:
'{"orderId":9007199254740993}' };
context.download(record);
const actual = await captured.text();
console.log('Incoming:', record.body);
console.log('Downloaded:', actual);
assert.ok(actual.includes('9007199254740992'), 'Expected current rounding
bug');
```
This extracts the original functions and only removes their TypeScript
types. The
assertion deliberately checks the current defect; it is not a passing fix
test.
The row's button wiring was inspected statically, not clicked in a browser.
### What Did You Expect to See?
Downloading the available `record.body` should preserve its content,
including
numeric tokens. Presentation formatting should not silently rewrite message
data.
This does not imply recovery of bytes already truncated or encoded by the
backend.
### What Did You See Instead?
```text
Incoming: {"orderId":9007199254740993}
Downloaded: {
"orderId": 9007199254740992
}
```
Additional source-function controls:
| Body value | Value in downloaded body |
| --- | --- |
| `9223372036854775807` | `9223372036854776000` |
| `9007199254740991` | unchanged |
| `"9007199254740993"` (JSON string) | unchanged |
| Plain text, not JSON | unchanged |
### Additional Context
-
[Formatter](https://github.com/apache/rocketmq-dashboard/blob/4c697f07acde460e2344375cb1f82669f5b270fd/web/src/pages/instance/message.tsx#L140-L146)
- [Download
handler](https://github.com/apache/rocketmq-dashboard/blob/4c697f07acde460e2344375cb1f82669f5b270fd/web/src/pages/instance/message.tsx#L730-L734)
- [Row
action](https://github.com/apache/rocketmq-dashboard/blob/4c697f07acde460e2344375cb1f82669f5b270fd/web/src/pages/instance/message.tsx#L838)
- The [copyable detail
view](https://github.com/apache/rocketmq-dashboard/blob/4c697f07acde460e2344375cb1f82669f5b270fd/web/src/pages/instance/message.tsx#L945-L959)
uses the same formatter. This is the same root cause, not a separate
feature request;
the actual clipboard interaction has not been tested.
#4759 / #4760 concern Go CLI passthrough precision, whereas this path is the
normal
message-page download. #4735 / #4737 concern AI redelivery, which is not
involved
here. Any proposed fix should account for the related body
encoding/truncation
concerns discussed in #2501 / #2571.
A small proposed direction is to preserve the available body string for
downloads
and copying, and agree on the presentation policy before changing the
display.
A component regression should click download and inspect the Blob, with
unsafe
integers, safe integers, quoted IDs, and plain text as controls.
This report was prepared with AI assistance and independently checked by
rerunning
the source-function probe. No production code was changed, and no browser
E2E,
Vitest suite, backend test, or full-stack validation is claimed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]