Fix Set Name Buffer reference for browser

Replace Node-only Buffer.byteLength with a TextEncoder-based UTF-8 byte
length helper so the Set Name page and byte counter work in the browser.

By specifier.
This commit is contained in:
Chris Troutner
2026-08-25 20:17:10 -07:00
parent 732248aee9
commit 230618d2a0
5 changed files with 59 additions and 3 deletions
+2 -1
View File
@@ -12,6 +12,7 @@ import { useNavigate } from 'react-router-dom'
// Local libraries
import MemoSetName from '../../../services/memo-set-name'
import SetNamePage from '../../../services/set-name-page'
import { byteLength } from '../../../services/utf8'
function SetName (props) {
const { appData } = props
@@ -22,7 +23,7 @@ function SetName (props) {
const [err, setErr] = useState('')
const [settingName, setSettingName] = useState(false)
const remaining = maxBytes - Buffer.byteLength(input, 'utf8')
const remaining = maxBytes - byteLength(input)
async function handleSubmit (event) {
event.preventDefault()
+2 -1
View File
@@ -17,6 +17,7 @@
*/
const MemoAction = require('./memo-action')
const { byteLength } = require('./utf8')
const MEMO_SET_NAME_PREFIX = '6d01'
const MAX_NAME_BYTES = 77
@@ -38,7 +39,7 @@ class MemoSetName extends MemoAction {
// A name is over-length when it exceeds the byte limit.
isTooLong (name) {
return Buffer.byteLength(name, 'utf8') > MAX_NAME_BYTES
return byteLength(name) > MAX_NAME_BYTES
}
// Compose and broadcast a Memo set-name transaction for the given name.
+2 -1
View File
@@ -15,6 +15,7 @@
const PageController = require('./page-controller')
const MemoSetName = require('./memo-set-name')
const { byteLength } = require('./utf8')
const SET_NAME_PATH = '/memo/set-name'
const ACCOUNT_PATH = '/account'
@@ -30,7 +31,7 @@ class SetNamePage extends PageController {
// Bytes remaining before the name limit is reached.
remainingCount () {
return MemoSetName.MAX_NAME_BYTES - Buffer.byteLength(this.input, 'utf8')
return MemoSetName.MAX_NAME_BYTES - byteLength(this.input)
}
// Set the in-flight setting-name flag.
+15
View File
@@ -0,0 +1,15 @@
/*
UTF-8 byte-length helper for browser and Node.
The Node global `Buffer` is not available in the browser, so byte counting
(used by the Memo set-name byte counter and length check) must not depend on
it. TextEncoder is available in both environments and reports the UTF-8 byte
length of a string.
*/
// Return the number of UTF-8 bytes in a string.
function byteLength (str) {
return new TextEncoder().encode(String(str)).length
}
module.exports = { byteLength }
+38
View File
@@ -0,0 +1,38 @@
/*
Unit tests for the UTF-8 byte-length helper (src/services/utf8.js).
The helper must report the same UTF-8 byte length as Node's Buffer without
depending on the Node-only `Buffer` global, so the browser build (which has
no Buffer) can count bytes for the Memo set-name counter and length check.
*/
'use strict'
const test = require('node:test')
const assert = require('node:assert/strict')
const { byteLength } = require('../../src/services/utf8')
test('byteLength matches Buffer.byteLength for ASCII text', () => {
for (const s of ['', 'trout', 'a longer name with spaces', 'x'.repeat(77)]) {
assert.equal(byteLength(s), Buffer.byteLength(s, 'utf8'))
}
})
test('byteLength matches Buffer.byteLength for multi-byte characters', () => {
for (const s of ['é', 'é'.repeat(38), '😀', '😀'.repeat(20), '日本語']) {
assert.equal(byteLength(s), Buffer.byteLength(s, 'utf8'))
}
})
test('byteLength counts UTF-8 bytes, not characters', () => {
// 'é' is 1 character but 2 UTF-8 bytes; an emoji is 1 character but 4 bytes.
assert.equal(byteLength('é'), 2)
assert.equal(byteLength('😀'), 4)
assert.equal(byteLength('a'), 1)
})
test('byteLength coerces non-string input to a string', () => {
assert.equal(byteLength(42), 2)
assert.equal(byteLength(null), 4) // String(null) === 'null'
})